diff --git a/Game/Game.vcxproj b/Game/Game.vcxproj
index a7dab41..3a99788 100644
--- a/Game/Game.vcxproj
+++ b/Game/Game.vcxproj
@@ -135,6 +135,6 @@ move "*.nfpack" "$(OutDir)assets\"
<_delete Include="$(OutDir)**\*" />
-
+
\ No newline at end of file
diff --git a/Game/src/Game.cpp b/Game/src/Game.cpp
index bd648f7..d966259 100644
--- a/Game/src/Game.cpp
+++ b/Game/src/Game.cpp
@@ -7,9 +7,10 @@ int main(int argc, char* argv[]) {
//app.setWindowIcon(...);
// app.setWindowCursor(...);
+ //Has to be on the heap for some reason
MainState* test = new MainState;
app.addState(test, "Main State");
- app.addDefaultState("Main State");
+ app.setDefaultState("Main State");
app.run();
diff --git a/Game/src/MainState.cpp b/Game/src/MainState.cpp
index 07e903a..70d308b 100644
--- a/Game/src/MainState.cpp
+++ b/Game/src/MainState.cpp
@@ -67,8 +67,11 @@ void MainState::update(double deltaTime) {
if (button.isClicked())
app->changeState("Main State");
- if (button.isClicked() || app->isKeyPressed(NFI_SPACE))
- sound.play();
+ if (button2.isClicked() || app->isKeyHeld(NFI_SPACE))
+ sound.play(true);
+
+ if (app->isKeyPressed(NFI_O))
+ sound.stop();
if (app->isKeyPressed(NFI_ESCAPE))
app->quit();
diff --git a/NothinFancy/src/Application.cpp b/NothinFancy/src/Application.cpp
index 080767c..14beb93 100644
--- a/NothinFancy/src/Application.cpp
+++ b/NothinFancy/src/Application.cpp
@@ -57,7 +57,7 @@ namespace nf {
Error("State \"" + (std::string)stateName + (std::string)"\" already exists!");
}
- void Application::addDefaultState(const std::string& stateName) {
+ void Application::setDefaultState(const std::string& stateName) {
if (!m_defaultStateAdded) {
if (m_states.find(stateName) != m_states.end()) {
m_defaultState = stateName;
@@ -299,7 +299,6 @@ namespace nf {
if (m_deltaTime >= m_minFrametime) {
lastFrame = std::chrono::steady_clock::now();
m_currentState->update(m_deltaTime);
- m_audio->updateSources();
m_currentState->render(*m_renderer);
m_renderer->doFrame(m_currentState->getCamera(), m_deltaTime);
if (m_stateChange)
@@ -318,9 +317,10 @@ namespace nf {
}
}
}
- delete m_audio;
+ m_audio->stopAllSounds();
m_currentState->onExit();
m_currentState->cleanup();
+ delete m_audio;
delete m_renderer;
}
@@ -332,7 +332,7 @@ namespace nf {
}
if (m_renderer->isFadeOutComplete()) {
- m_audio->cleanup();
+ m_audio->stopAllSounds();
m_currentState->onExit();
m_currentState->cleanup();
m_currentState = m_states[m_nextState];
diff --git a/NothinFancy/src/AudioEngine.cpp b/NothinFancy/src/AudioEngine.cpp
index 5f27c80..e4c9cbc 100644
--- a/NothinFancy/src/AudioEngine.cpp
+++ b/NothinFancy/src/AudioEngine.cpp
@@ -1,66 +1,200 @@
#include "AudioEngine.h"
#include "Application.h"
+#include "Entity.h"
namespace nf {
AudioEngine::AudioEngine(Application* app) :
m_app(app),
m_engine(nullptr),
- m_masterVoice(nullptr)
+ m_masterVoice(nullptr),
+ m_isActive(false),
+ m_threadRunning(false),
+ m_clear(false)
{
- CoInitializeEx(nullptr, COINIT_MULTITHREADED);
- XAudio2Create(&m_engine, XAUDIO2_DEBUG_ENGINE);
+ HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ if (FAILED(hr))
+ Error("Could not initialize COM!");
+ hr = XAudio2Create(&m_engine);
+ if (FAILED(hr))
+ Error("Could not initialize the audio engine!");
+#ifdef _DEBUG
XAUDIO2_DEBUG_CONFIGURATION debug = { 0 };
debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
debug.BreakMask = XAUDIO2_LOG_ERRORS;
m_engine->SetDebugConfiguration(&debug, 0);
- m_engine->CreateMasteringVoice(&m_masterVoice);
- DWORD channelMask;
- m_masterVoice->GetChannelMask(&channelMask);
- X3DAudioInitialize(channelMask, X3DAUDIO_SPEED_OF_SOUND, m_x3d);
+#endif
+ hr = m_engine->CreateMasteringVoice(&m_masterVoice);
+ if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
+ m_isActive = false;
+ else if (SUCCEEDED(hr))
+ m_isActive = true;
+ else
+ Error("Could not initialize the audio engine!");
+ m_threadRunning = true;
+ m_thread = std::thread(&AudioEngine::runAudioThread, this);
}
- void AudioEngine::updateSources() {
- for (unsigned int i = 0; i < m_voices.size(); i++) {
- XAUDIO2_VOICE_STATE state;
- m_voices[i]->GetState(&state);
- if (state.BuffersQueued == 0) {
- m_voices[i]->Stop();
- m_voices[i]->FlushSourceBuffers();
- m_voices[i]->DestroyVoice();
- m_voices.erase(m_voices.begin() + i);
- i = 0;
+ bool AudioEngine::isActive() {
+ if (!m_isActive) {
+ HRESULT hr = m_engine->CreateMasteringVoice(&m_masterVoice);
+ if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
+ return false;
+ else if (hr == S_OK) {
+ m_isActive = true;
+ return true;
+ }
+ else {
+ Error("Could not initialize audio!");
+ return false;
}
}
+ else
+ return true;
}
- IXAudio2SourceVoice* AudioEngine::getNewSourceVoice(WAVEFORMATEXTENSIBLE* fmt) {
- IXAudio2SourceVoice* s;
- HRESULT hr = m_engine->CreateSourceVoice(&s, &fmt->Format, XAUDIO2_VOICE_USEFILTER);
- m_voices.push_back(s);
- return s;
- }
-
- IXAudio2MasteringVoice* AudioEngine::getMasterVoice() {
- return m_masterVoice;
- }
-
- X3DAUDIO_HANDLE* AudioEngine::getX3DAudioInstance() {
- return &m_x3d;
- }
-
- void AudioEngine::cleanup() {
- for (unsigned int i = 0; i < m_voices.size(); i++) {
- m_voices[i]->Stop();
- m_voices[i]->FlushSourceBuffers();
- m_voices[i]->DestroyVoice();
+ void AudioEngine::runAudioThread() {
+#ifdef _DEBUG
+ SetThreadDescription(GetCurrentThread(), L"Audio Thread");
+#endif
+ //Wait to initialize stuff until the master voice is created if it hasn't been already
+ while (!m_isActive) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
- m_voices.clear();
+
+ DWORD cm;
+ m_masterVoice->GetChannelMask(&cm);
+ X3DAUDIO_HANDLE x3d;
+ X3DAudioInitialize(cm, X3DAUDIO_SPEED_OF_SOUND, x3d);
+ X3DAUDIO_LISTENER listener;
+ std::memset(&listener, 0, sizeof(X3DAUDIO_LISTENER));
+ listener.OrientTop = X3DAUDIO_VECTOR(0.0, 1.0, 0.0);
+ X3DAUDIO_EMITTER emitter;
+ std::memset(&emitter, 0, sizeof(X3DAUDIO_EMITTER));
+ emitter.OrientTop = X3DAUDIO_VECTOR(0.0, 1.0, 0.0);
+ emitter.OrientFront = X3DAUDIO_VECTOR(0.0, 0.0, 1.0);
+ emitter.CurveDistanceScaler = 1.0f;
+ X3DAUDIO_DSP_SETTINGS x3dSettings;
+ std::memset(&x3dSettings, 0, sizeof(X3DAUDIO_DSP_SETTINGS));
+ float matrix[20] = { 0 };
+ x3dSettings.pMatrixCoefficients = matrix;
+ float az[20] = { 0 };
+ emitter.pChannelAzimuths = az;
+ XAUDIO2_FILTER_PARAMETERS filter = { LowPassFilter, 1.0, 1.0 };
+ XAUDIO2_VOICE_STATE state;
+ Vec3 temp;
+
+ while (m_threadRunning) {
+ if (m_isActive && Application::getApp()->getCurrentState()->isRunning()) {
+ //Update listener position
+ temp = Application::getApp()->getCurrentState()->getCamera()->getPosition();
+ listener.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z);
+ temp = Application::getApp()->getCurrentState()->getCamera()->getRotation();
+ listener.OrientFront = X3DAUDIO_VECTOR((float)temp.x, 0.0f, (float)-temp.z);
+
+ //Stop all sounds if requested
+ if (m_clear)
+ clearSounds();
+
+ //Update sounds
+ for (SoundData& curr : m_sounds) {
+ //Skip finished sounds
+ if (curr.finished) continue;
+ //Start sound if not started yet
+ if (curr.start) {
+ curr.start = false;
+ IXAudio2SourceVoice* source;
+ HRESULT hr = m_engine->CreateSourceVoice(&source, (WAVEFORMATEX*)curr.format, XAUDIO2_VOICE_USEFILTER);
+ if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) {
+ m_isActive = false;
+ m_clear = true;
+ break;
+ }
+ else if (!SUCCEEDED(hr))
+ Error("Could not play sound!");
+ curr.voice = source;
+ curr.voice->SubmitSourceBuffer(curr.buffer);
+ curr.voice->SetVolume(curr.volume);
+ curr.voice->Start();
+ }
+ //Finish sound
+ curr.voice->GetState(&state);
+ if (state.BuffersQueued == 0) {
+ curr.finished = true;
+ continue;
+ }
+
+ //Update playing sound
+ if (curr.playAtPosition)
+ temp = curr.position;
+ if (curr.trackToEntity)
+ temp = curr.trackedEntity->getPosition();
+
+ if (curr.playAtPosition || curr.trackToEntity) {
+ int ch = curr.format->Format.nChannels;
+ emitter.ChannelCount = ch;
+ x3dSettings.SrcChannelCount = ch;
+ x3dSettings.DstChannelCount = ch;
+ emitter.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z);
+ X3DAudioCalculate(x3d, &listener, &emitter, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, &x3dSettings);
+ float temp2 = matrix[1];
+ matrix[1] = matrix[2];
+ matrix[2] = temp2;
+ curr.voice->SetOutputMatrix(m_masterVoice, ch, ch, matrix);
+ curr.voice->SetFrequencyRatio(x3dSettings.DopplerFactor);
+ filter.Frequency = 2.0f * std::sinf(X3DAUDIO_PI / 6.0f * x3dSettings.LPFDirectCoefficient);
+ curr.voice->SetFilterParameters(&filter);
+ }
+ }
+
+ //Delete all finished sounds from the list
+ for (size_t i = 0; i < m_sounds.size(); i++) {
+ if (m_sounds[i].finished) {
+ m_sounds[i].voice->Stop();
+ m_sounds[i].voice->FlushSourceBuffers();
+ m_sounds[i].voice->DestroyVoice();
+ m_sounds.erase(m_sounds.begin() + i);
+ }
+ }
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ }
+
+ //Cleanup
+ clearSounds();
+ m_masterVoice->DestroyVoice();
+ }
+
+ void AudioEngine::addSound(SoundData& data) {
+ m_sounds.push_back(data);
+ }
+
+ void AudioEngine::stopSound(const XAUDIO2_BUFFER* buffer) {
+ //Maybe should move to audio thread somehow?
+ for (SoundData& curr : m_sounds) {
+ if (std::memcmp(curr.buffer, buffer, sizeof(XAUDIO2_BUFFER)) == 0)
+ curr.finished = true;
+ }
+ }
+
+ void AudioEngine::stopAllSounds() {
+ m_clear = true;
+ }
+
+ void AudioEngine::clearSounds() {
+ m_clear = false;
+ for (SoundData& curr : m_sounds) {
+ if (curr.start) continue;
+ curr.voice->Stop();
+ curr.voice->FlushSourceBuffers();
+ curr.voice->DestroyVoice();
+ }
+ m_sounds.clear();
}
AudioEngine::~AudioEngine() {
- cleanup();
- m_masterVoice->DestroyVoice();
+ m_threadRunning = false;
+ m_thread.join();
m_engine->Release();
CoUninitialize();
}
diff --git a/NothinFancy/src/Gamestate.cpp b/NothinFancy/src/Gamestate.cpp
index ac45254..c4f8556 100644
--- a/NothinFancy/src/Gamestate.cpp
+++ b/NothinFancy/src/Gamestate.cpp
@@ -65,5 +65,6 @@ namespace nf {
delete camera;
app = nullptr;
+ m_running = false;
}
}
\ No newline at end of file
diff --git a/NothinFancy/src/NFObject/Sound.cpp b/NothinFancy/src/NFObject/Sound.cpp
index cfd7a42..2e5f6e8 100644
--- a/NothinFancy/src/NFObject/Sound.cpp
+++ b/NothinFancy/src/NFObject/Sound.cpp
@@ -3,19 +3,17 @@
#include "Application.h"
#include "Assets.h"
#include "Entity.h"
-#include "Utility.h"
namespace nf {
Sound::Sound() :
m_constructed(false),
- m_dataSize(0),
m_volume(1.0f),
m_usePos(false),
+ m_useEntity(false),
m_format({ 0 }),
+ m_xBuffer({ 0 }),
m_buffer(nullptr),
- m_currentVoice(nullptr),
- m_targetEntity(nullptr),
- m_soundPos(0.0)
+ m_targetEntity(nullptr)
{
}
@@ -38,15 +36,15 @@ namespace nf {
size_t dataPos;
if ((dataPos = data.find("data")) == std::string::npos)
Error("Sound asset not of correct m_format!");
- m_dataSize = *(unsigned int*)&data[dataPos + 4];
- m_buffer = new unsigned char[m_dataSize];
- std::memcpy(m_buffer, &data[dataPos + 8], m_dataSize);
+ unsigned int dataSize = *(unsigned int*)&data[dataPos + 4];
+ m_buffer = new unsigned char[dataSize];
+ std::memcpy(m_buffer, &data[dataPos + 8], dataSize);
+ m_xBuffer.pAudioData = m_buffer;
+ m_xBuffer.AudioBytes = dataSize;
+ m_xBuffer.Flags = XAUDIO2_END_OF_STREAM;
- m_emitter = { 0 };
- m_emitter.ChannelCount = 2;
- m_emitter.CurveDistanceScaler = 1.0;
-
- Application::getApp()->getCurrentState()->m_nfObjects.push_back(this);
+ if (!Application::getApp()->getCurrentState()->isRunning())
+ Application::getApp()->getCurrentState()->m_nfObjects.push_back(this);
}
void Sound::setVolume(double volume) {
@@ -55,72 +53,28 @@ namespace nf {
void Sound::setEntity(Entity& entity) {
m_targetEntity = &entity;
+ m_useEntity = true;
m_usePos = false;
}
void Sound::setPosition(const Vec3& position) {
m_soundPos = position;
m_usePos = true;
+ m_useEntity = false;
}
void Sound::play(bool loop) {
- m_currentVoice = Application::getApp()->getAudioEngine()->getNewSourceVoice(&m_format);
- m_currentVoice->SetVolume(m_volume);
+ if (!Application::getApp()->getAudioEngine()->isActive()) return;
- XAUDIO2_BUFFER xBuffer = { 0 };
- xBuffer.pAudioData = m_buffer;
- xBuffer.AudioBytes = m_dataSize;
if (loop)
- xBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
+ m_xBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
- if (m_usePos || m_targetEntity) {
- if (m_usePos)
- m_emitter.Position = X3DAUDIO_VECTOR((float)m_soundPos.x, (float)m_soundPos.y, (float)-m_soundPos.z);
- else if (m_targetEntity) {
- Vec3 temp = m_targetEntity->getPosition();
- m_emitter.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z);
- }
- m_emitter.OrientFront = X3DAUDIO_VECTOR(0.0, 0.0, 1.0);
- m_emitter.OrientTop = X3DAUDIO_VECTOR(0.0, 1.0, 0.0);
- float az[2] = { 0 };
- m_emitter.pChannelAzimuths = az;
- Vec3 temp = Application::getApp()->getCurrentState()->getCamera()->getPosition();
- m_listener.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z);
- temp = Application::getApp()->getCurrentState()->getCamera()->getRotation();
- m_listener.OrientFront = X3DAUDIO_VECTOR((float)temp.x, 0.0f, (float)-temp.z);
- m_listener.OrientTop = X3DAUDIO_VECTOR(0.0, 1.0, 0.0);
- X3DAUDIO_DSP_SETTINGS settings = { 0 };
- settings.SrcChannelCount = 2;
- settings.DstChannelCount = 2;
- float matrix[4] = { 0 };
- settings.pMatrixCoefficients = matrix;
-
- IXAudio2MasteringVoice* master = Application::getApp()->getAudioEngine()->getMasterVoice();
- X3DAUDIO_HANDLE* instance = Application::getApp()->getAudioEngine()->getX3DAudioInstance();
- X3DAudioCalculate(*instance, &m_listener, &m_emitter, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, &settings);
- float temp2 = settings.pMatrixCoefficients[1];
- settings.pMatrixCoefficients[1] = settings.pMatrixCoefficients[2];
- settings.pMatrixCoefficients[2] = temp2;
- m_currentVoice->SetOutputMatrix(master, 2, 2, settings.pMatrixCoefficients);
- m_currentVoice->SetFrequencyRatio(settings.DopplerFactor);
- XAUDIO2_FILTER_PARAMETERS lpf = { LowPassFilter, 2.0f * std::sinf(X3DAUDIO_PI / 6.0f * settings.LPFDirectCoefficient), 1.0f };
- m_currentVoice->SetFilterParameters(&lpf);
- }
-
- m_currentVoice->SubmitSourceBuffer(&xBuffer);
- m_currentVoice->Start();
+ SoundData sd = { &m_format, &m_xBuffer, nullptr, true, m_volume, m_useEntity, m_targetEntity, m_usePos, m_soundPos };
+ Application::getApp()->getAudioEngine()->addSound(sd);
}
void Sound::stop() {
- if (m_currentVoice) {
- XAUDIO2_VOICE_STATE state;
- m_currentVoice->GetState(&state);
- if (state.BuffersQueued > 0) {
- m_currentVoice->Stop();
- m_currentVoice->FlushSourceBuffers();
- m_currentVoice = nullptr;
- }
- }
+ Application::getApp()->getAudioEngine()->stopSound(&m_xBuffer);
}
void Sound::destroy() {
@@ -129,10 +83,8 @@ namespace nf {
m_buffer = nullptr;
}
m_constructed = false;
- m_dataSize = 0;
m_volume = 1.0f;
m_format = { 0 };
- m_currentVoice = nullptr;
}
Sound::~Sound() {
diff --git a/NothinFancy/src/include/Application.h b/NothinFancy/src/include/Application.h
index cc6e7d3..3fa5200 100644
--- a/NothinFancy/src/include/Application.h
+++ b/NothinFancy/src/include/Application.h
@@ -21,7 +21,7 @@ namespace nf {
void setWindowCursor(HCURSOR hCursor);
AudioEngine* getAudioEngine() const;
void addState(Gamestate* state, const std::string& stateName);
- void addDefaultState(const std::string& stateName);
+ void setDefaultState(const std::string& stateName);
const std::string& getDefaultState();
void run();
bool isCustomWindowIcon();
diff --git a/NothinFancy/src/include/AudioEngine.h b/NothinFancy/src/include/AudioEngine.h
index 6eada2e..a273dec 100644
--- a/NothinFancy/src/include/AudioEngine.h
+++ b/NothinFancy/src/include/AudioEngine.h
@@ -1,27 +1,50 @@
#pragma once
#include
+#include
#include
#include
+#include "Utility.h"
+
namespace nf {
+ class Entity;
+
+ struct SoundData {
+ WAVEFORMATEXTENSIBLE* format;
+ XAUDIO2_BUFFER* buffer;
+ IXAudio2SourceVoice* voice;
+ bool start;
+ float volume;
+ bool trackToEntity;
+ Entity* trackedEntity;
+ bool playAtPosition;
+ Vec3 position;
+ bool finished = false;
+ };
+
class Application;
class AudioEngine {
public:
AudioEngine(Application* app);
- void updateSources();
- IXAudio2SourceVoice* getNewSourceVoice(WAVEFORMATEXTENSIBLE* fmt);
- IXAudio2MasteringVoice* getMasterVoice();
- X3DAUDIO_HANDLE* getX3DAudioInstance();
+ bool isActive();
+ void runAudioThread();
+ void addSound(SoundData& data);
+ void stopSound(const XAUDIO2_BUFFER* buffer);
- void cleanup();
+ void stopAllSounds();
~AudioEngine();
private:
+ void clearSounds();
+
Application* m_app;
IXAudio2* m_engine;
- X3DAUDIO_HANDLE m_x3d;
IXAudio2MasteringVoice* m_masterVoice;
- std::vector m_voices;
+ bool m_isActive;
+ bool m_threadRunning;
+ std::thread m_thread;
+ std::vector m_sounds;
+ bool m_clear;
};
}
\ No newline at end of file
diff --git a/NothinFancy/src/include/Sound.h b/NothinFancy/src/include/Sound.h
index 2463f68..77dd030 100644
--- a/NothinFancy/src/include/Sound.h
+++ b/NothinFancy/src/include/Sound.h
@@ -1,8 +1,6 @@
#pragma once
-#include
-#include
-
#include "NFObject.h"
+#include "AudioEngine.h"
#include "Utility.h"
namespace nf {
@@ -24,15 +22,13 @@ namespace nf {
~Sound();
private:
bool m_constructed;
- unsigned int m_dataSize;
float m_volume;
bool m_usePos;
+ bool m_useEntity;
WAVEFORMATEXTENSIBLE m_format;
+ XAUDIO2_BUFFER m_xBuffer;
unsigned char* m_buffer;
- IXAudio2SourceVoice* m_currentVoice;
Entity* m_targetEntity;
Vec3 m_soundPos;
- X3DAUDIO_EMITTER m_emitter;
- X3DAUDIO_LISTENER m_listener;
};
}
\ No newline at end of file