diff --git a/src/dawn/visualnovel/scene/SimpleVNScene.cpp b/src/dawn/visualnovel/scene/SimpleVNScene.cpp index 7b32f586..d0d8133d 100644 --- a/src/dawn/visualnovel/scene/SimpleVNScene.cpp +++ b/src/dawn/visualnovel/scene/SimpleVNScene.cpp @@ -32,6 +32,10 @@ void SimpleVNScene::stage() { this->camera->getRenderTarget()->getHeight(), camera->fov ); + + // Audio + auto listenerItem = this->createSceneItem(); + this->audioListener = listenerItem->addComponent(); // UI this->canvas = UICanvas::create(this); diff --git a/src/dawn/visualnovel/scene/SimpleVNScene.hpp b/src/dawn/visualnovel/scene/SimpleVNScene.hpp index 7172304e..895e739f 100644 --- a/src/dawn/visualnovel/scene/SimpleVNScene.hpp +++ b/src/dawn/visualnovel/scene/SimpleVNScene.hpp @@ -25,6 +25,7 @@ namespace Dawn { SimpleVisualNovelBackground *background = nullptr; VisualNovelFader *vnFader = nullptr; VisualNovelManager *vnManager = nullptr; + AudioListener *audioListener = nullptr; virtual void vnStage() = 0; virtual IVisualNovelEvent * getVNEvent() = 0; diff --git a/src/dawnopenal/audio/AudioManager.cpp b/src/dawnopenal/audio/AudioManager.cpp index e76af8a2..b3c32260 100644 --- a/src/dawnopenal/audio/AudioManager.cpp +++ b/src/dawnopenal/audio/AudioManager.cpp @@ -18,8 +18,6 @@ void AudioManager::init() { this->context = alcCreateContext(this->device, NULL); if(!alcMakeContextCurrent(this->context)) assertUnreachable(); - - alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); } void AudioManager::update() { diff --git a/src/dawnopenal/scene/components/audio/AudioSource.cpp b/src/dawnopenal/scene/components/audio/AudioSource.cpp index 943d47e6..1f36a426 100644 --- a/src/dawnopenal/scene/components/audio/AudioSource.cpp +++ b/src/dawnopenal/scene/components/audio/AudioSource.cpp @@ -4,7 +4,7 @@ // https://opensource.org/licenses/MIT #include "AudioSource.hpp" -#include "scene/SceneItem.hpp" +#include "game/DawnGame.hpp" using namespace Dawn; @@ -12,20 +12,71 @@ AudioSource::AudioSource(SceneItem *i) : SceneItemComponent(i) { } +void AudioSource::updateAudioSource() { + if(!this->ready || data == nullptr || !data->ready) return; + + switch(this->requestedAudioState) { + // When the engine wants the sound to stop + case AUDIO_SOURCE_STATE_STOPPED: + if(this->currentAudioState == AUDIO_SOURCE_STATE_STOPPED) return; + this->currentAudioState = AUDIO_SOURCE_STATE_STOPPED; + alSourceStop(this->source); + this->eventStopped.invoke(); + break; + + // When the engine wants the sound to pause + case AUDIO_SOURCE_STATE_PAUSED: + if(this->currentAudioState != AUDIO_SOURCE_STATE_PLAYING) return; + this->currentAudioState = AUDIO_SOURCE_STATE_PAUSED; + alSourcePause(this->source); + this->eventPaused.invoke(); + break; + + // When the engine wants the sound to play... + case AUDIO_SOURCE_STATE_PLAYING: + switch(this->playMode) { + // This should be playing, right now. + case AUDIO_PLAY_MODE_ALWAYS: + if(this->currentAudioState == AUDIO_SOURCE_STATE_PLAYING) return; + this->currentAudioState = AUDIO_SOURCE_STATE_PLAYING; + alSourcePlay(this->source); + this->eventPlaying.invoke(); + break; + + case AUDIO_PLAY_MODE_UNPAUSED: + if(this->getGame()->timeManager.isPaused) { + if(this->currentAudioState != AUDIO_SOURCE_STATE_PLAYING) return; + this->currentAudioState = AUDIO_SOURCE_STATE_PAUSED; + alSourcePause(this->source); + this->eventPaused.invoke(); + } else { + if(this->currentAudioState == AUDIO_SOURCE_STATE_PLAYING) return; + this->currentAudioState = AUDIO_SOURCE_STATE_PLAYING; + alSourcePlay(this->source); + this->eventPlaying.invoke(); + } + break; + + default: + assertUnreachable(); + } + break; + + default: + assertUnreachable(); + } +} + void AudioSource::onStart() { alGenSources((ALuint)1, &this->source); // In future these will probably be tied to the layer alSourcef(this->source, AL_PITCH, 1); - // alSourcef(this->source, AL_GAIN, AL_MAX_GAIN); + alSourcef(this->source, AL_GAIN, 1); glm::vec3 position = this->transform->getLocalPosition(); alSource3f(this->source, AL_POSITION, position.x, position.y, position.z); - // alSourcei(this->source, AL_SOURCE_RELATIVE, AL_TRUE); - // alSourcef(this->source, AL_REFERENCE_DISTANCE, 0); - // alSourcef(this->source, AL_ROLLOFF_FACTOR, 0); - // Velocity is always zero for now alSource3f(this->source, AL_VELOCITY, 0, 0, 0); @@ -37,13 +88,17 @@ void AudioSource::onStart() { alSourcei(source, AL_BUFFER, this->data->buffer); } - // Playing - if(this->playing) alSourcePlay(this->source); + // Ready. + this->ready = true; + + // Update the source now we are ready. + this->updateAudioSource(); // Listen for events this->transform->eventTransformUpdated.addListener(this, &AudioSource::onTransformUpdate); + this->getGame()->timeManager.eventTimePaused.addListener(this, &AudioSource::onGamePause); + this->getGame()->timeManager.eventTimeResumed.addListener(this, &AudioSource::onGameUnpause); - this->ready = true; } bool_t AudioSource::isLooping() { @@ -55,30 +110,63 @@ void AudioSource::setLoop(bool_t loop) { if(this->ready) alSourcei(this->source, AL_LOOPING, loop); } -bool_t AudioSource::isPlaying() { - return this->playing; +AudioSourceState AudioSource::getPlayingState() { + return this->requestedAudioState; +} + +void AudioSource::setPlayingState(enum AudioSourceState state) { + this->requestedAudioState = state; + this->updateAudioSource(); +} + +AudioSourceState AudioSource::getRealState() { + return this->currentAudioState; } void AudioSource::play() { - this->playing = true; - if(this->ready && data != nullptr && data->ready) { - alSourcePlay(this->source); - } + this->setPlayingState(AUDIO_SOURCE_STATE_PLAYING); } +void AudioSource::pause() { + this->setPlayingState(AUDIO_SOURCE_STATE_PAUSED); +} + +void AudioSource::stop() { + this->setPlayingState(AUDIO_SOURCE_STATE_STOPPED); +} + +// void AudioSource::rewind() { +// if(this->ready && data != nullptr && data->ready) { +// alSourceRewind(this->source); +// } +// } + AudioData * AudioSource::getAudioData() { return this->data; } void AudioSource::setAudioData(AudioData *data) { - this->data = data; + // Set up source. if(this->ready && data != nullptr && data->ready) { alSourcei(source, AL_BUFFER, data->buffer); } + this->data = data; + this->updateAudioSource(); +} + +enum AudioSourcePlayMode AudioSource::getPlayMode() { + return this->playMode; +} + +void AudioSource::setPlayMode(enum AudioSourcePlayMode playMode) { + this->playMode = playMode; + this->updateAudioSource(); } void AudioSource::onDispose() { this->transform->eventTransformUpdated.removeListener(this, &AudioSource::onTransformUpdate); + this->getGame()->timeManager.eventTimePaused.removeListener(this, &AudioSource::onGamePause); + this->getGame()->timeManager.eventTimeResumed.removeListener(this, &AudioSource::onGameUnpause); this->ready = false; alDeleteSources((ALuint)1, &this->source); @@ -87,4 +175,12 @@ void AudioSource::onDispose() { void AudioSource::onTransformUpdate() { glm::vec3 position = this->transform->getWorldPosition(); alSource3f(this->source, AL_POSITION, position.x, position.y, position.z); +} + +void AudioSource::onGamePause() { + this->updateAudioSource(); +} + +void AudioSource::onGameUnpause() { + this->updateAudioSource(); } \ No newline at end of file diff --git a/src/dawnopenal/scene/components/audio/AudioSource.hpp b/src/dawnopenal/scene/components/audio/AudioSource.hpp index 0f9e3ffb..7488b0ca 100644 --- a/src/dawnopenal/scene/components/audio/AudioSource.hpp +++ b/src/dawnopenal/scene/components/audio/AudioSource.hpp @@ -9,6 +9,17 @@ #include "audio/AudioData.hpp" namespace Dawn { + enum AudioSourceState { + AUDIO_SOURCE_STATE_STOPPED, + AUDIO_SOURCE_STATE_PLAYING, + AUDIO_SOURCE_STATE_PAUSED + }; + + enum AudioSourcePlayMode { + AUDIO_PLAY_MODE_ALWAYS, + AUDIO_PLAY_MODE_UNPAUSED + }; + class AudioSource : public SceneItemComponent { private: ALuint source; @@ -16,13 +27,27 @@ namespace Dawn { // Settings bool_t loop = false; - bool_t playing = false; + enum AudioSourceState requestedAudioState = AUDIO_SOURCE_STATE_STOPPED; + enum AudioSourceState currentAudioState = AUDIO_SOURCE_STATE_STOPPED; int32_t layer = 0; AudioData *data = nullptr; + AudioSourcePlayMode playMode = AUDIO_PLAY_MODE_UNPAUSED; + /** + * Internally update the audio's state based on the current settings. + */ + void updateAudioSource(); + + // Events void onTransformUpdate(); + void onGamePause(); + void onGameUnpause(); public: + Event<> eventPlaying; + Event<> eventPaused; + Event<> eventStopped; + /** * Creates an Audio Source item component. * @@ -44,9 +69,55 @@ namespace Dawn { */ void setLoop(bool_t loop); - bool_t isPlaying(); + /** + * Returns the requested playing state of the source. Due to some weird + * limitations of hardware, as well as some nice controls to decide how + * sources should play, this is basically "What you would like the sound + * to do" mode, so you really should be controlling this value where + * possible. + * + * @return The requested playing state. + */ + AudioSourceState getPlayingState(); + + /** + * Sets the ideal playing state you want of this audio source. + * + * @param state State to set. + */ + void setPlayingState(enum AudioSourceState state); + + /** + * Returns the real current state of the sound. Refer to getPlayingState + * but basically the actually requested play state and what the hardware + * and internal logic is doing may result in the actual state being a + * little different. You cannot control this, but you can read it. + * + * @return The actual current playing state. + */ + AudioSourceState getRealState(); + + /** + * Plays the audio source. + */ void play(); + /** + * Pauses the audio source. + */ + void pause(); + + /** + * Stops the audio source. + */ + void stop(); + + /** + * Rewinds the audio source. At the time of writing this comment (23017) I + * am unsure of the behaviour when rewinding whilst the source is active. + */ + // void rewind(); + /** * Returns the current audio data for this source. * @@ -62,6 +133,20 @@ namespace Dawn { */ void setAudioData(AudioData *data); + /** + * Returns the play mode for the source. + * + * @return Current play mode. + */ + enum AudioSourcePlayMode getPlayMode(); + + /** + * Sets the play mode for the source. + * + * @param mode Play Mode to use. + */ + void setPlayMode(enum AudioSourcePlayMode mode); + void onStart() override; void onDispose() override; }; diff --git a/src/dawnpokergame/scenes/Scene_1.hpp b/src/dawnpokergame/scenes/Scene_1.hpp index 5deae052..78a32dea 100644 --- a/src/dawnpokergame/scenes/Scene_1.hpp +++ b/src/dawnpokergame/scenes/Scene_1.hpp @@ -22,18 +22,16 @@ namespace Dawn { this->death = DeathPrefab::create(this); // this->death->vnCharacter.setOpacity(0); - auto listenerItem = this->createSceneItem(); - auto listener = listenerItem->addComponent(); - auto sourceItem = this->createSceneItem(); auto source = sourceItem->addComponent(); - source->transform->setLocalPosition(glm::vec3(-1, 0, 0)); + source->transform->setLocalPosition(glm::vec3(1, 0, 0)); auto data = new AudioData(); data->init(); source->setAudioData(data); source->play(); + source->setLoop(true); } void onSceneEnded() {