Really nice audio API

This commit is contained in:
2023-01-17 11:53:34 -08:00
parent 9168348e6b
commit a4ad5a3ac4
6 changed files with 206 additions and 24 deletions

View File

@ -32,6 +32,10 @@ void SimpleVNScene::stage() {
this->camera->getRenderTarget()->getHeight(), this->camera->getRenderTarget()->getHeight(),
camera->fov camera->fov
); );
// Audio
auto listenerItem = this->createSceneItem();
this->audioListener = listenerItem->addComponent<AudioListener>();
// UI // UI
this->canvas = UICanvas::create(this); this->canvas = UICanvas::create(this);

View File

@ -25,6 +25,7 @@ namespace Dawn {
SimpleVisualNovelBackground *background = nullptr; SimpleVisualNovelBackground *background = nullptr;
VisualNovelFader *vnFader = nullptr; VisualNovelFader *vnFader = nullptr;
VisualNovelManager *vnManager = nullptr; VisualNovelManager *vnManager = nullptr;
AudioListener *audioListener = nullptr;
virtual void vnStage() = 0; virtual void vnStage() = 0;
virtual IVisualNovelEvent * getVNEvent() = 0; virtual IVisualNovelEvent * getVNEvent() = 0;

View File

@ -18,8 +18,6 @@ void AudioManager::init() {
this->context = alcCreateContext(this->device, NULL); this->context = alcCreateContext(this->device, NULL);
if(!alcMakeContextCurrent(this->context)) assertUnreachable(); if(!alcMakeContextCurrent(this->context)) assertUnreachable();
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
} }
void AudioManager::update() { void AudioManager::update() {

View File

@ -4,7 +4,7 @@
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "AudioSource.hpp" #include "AudioSource.hpp"
#include "scene/SceneItem.hpp" #include "game/DawnGame.hpp"
using namespace Dawn; 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() { void AudioSource::onStart() {
alGenSources((ALuint)1, &this->source); alGenSources((ALuint)1, &this->source);
// In future these will probably be tied to the layer // In future these will probably be tied to the layer
alSourcef(this->source, AL_PITCH, 1); 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(); glm::vec3 position = this->transform->getLocalPosition();
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z); 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 // Velocity is always zero for now
alSource3f(this->source, AL_VELOCITY, 0, 0, 0); alSource3f(this->source, AL_VELOCITY, 0, 0, 0);
@ -37,13 +88,17 @@ void AudioSource::onStart() {
alSourcei(source, AL_BUFFER, this->data->buffer); alSourcei(source, AL_BUFFER, this->data->buffer);
} }
// Playing // Ready.
if(this->playing) alSourcePlay(this->source); this->ready = true;
// Update the source now we are ready.
this->updateAudioSource();
// Listen for events // Listen for events
this->transform->eventTransformUpdated.addListener(this, &AudioSource::onTransformUpdate); 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() { bool_t AudioSource::isLooping() {
@ -55,30 +110,63 @@ void AudioSource::setLoop(bool_t loop) {
if(this->ready) alSourcei(this->source, AL_LOOPING, loop); if(this->ready) alSourcei(this->source, AL_LOOPING, loop);
} }
bool_t AudioSource::isPlaying() { AudioSourceState AudioSource::getPlayingState() {
return this->playing; return this->requestedAudioState;
}
void AudioSource::setPlayingState(enum AudioSourceState state) {
this->requestedAudioState = state;
this->updateAudioSource();
}
AudioSourceState AudioSource::getRealState() {
return this->currentAudioState;
} }
void AudioSource::play() { void AudioSource::play() {
this->playing = true; this->setPlayingState(AUDIO_SOURCE_STATE_PLAYING);
if(this->ready && data != nullptr && data->ready) {
alSourcePlay(this->source);
}
} }
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() { AudioData * AudioSource::getAudioData() {
return this->data; return this->data;
} }
void AudioSource::setAudioData(AudioData *data) { void AudioSource::setAudioData(AudioData *data) {
this->data = data; // Set up source.
if(this->ready && data != nullptr && data->ready) { if(this->ready && data != nullptr && data->ready) {
alSourcei(source, AL_BUFFER, data->buffer); 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() { void AudioSource::onDispose() {
this->transform->eventTransformUpdated.removeListener(this, &AudioSource::onTransformUpdate); 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; this->ready = false;
alDeleteSources((ALuint)1, &this->source); alDeleteSources((ALuint)1, &this->source);
@ -87,4 +175,12 @@ void AudioSource::onDispose() {
void AudioSource::onTransformUpdate() { void AudioSource::onTransformUpdate() {
glm::vec3 position = this->transform->getWorldPosition(); glm::vec3 position = this->transform->getWorldPosition();
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z); alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
}
void AudioSource::onGamePause() {
this->updateAudioSource();
}
void AudioSource::onGameUnpause() {
this->updateAudioSource();
} }

View File

@ -9,6 +9,17 @@
#include "audio/AudioData.hpp" #include "audio/AudioData.hpp"
namespace Dawn { 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 { class AudioSource : public SceneItemComponent {
private: private:
ALuint source; ALuint source;
@ -16,13 +27,27 @@ namespace Dawn {
// Settings // Settings
bool_t loop = false; 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; int32_t layer = 0;
AudioData *data = nullptr; 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 onTransformUpdate();
void onGamePause();
void onGameUnpause();
public: public:
Event<> eventPlaying;
Event<> eventPaused;
Event<> eventStopped;
/** /**
* Creates an Audio Source item component. * Creates an Audio Source item component.
* *
@ -44,9 +69,55 @@ namespace Dawn {
*/ */
void setLoop(bool_t loop); 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(); 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. * Returns the current audio data for this source.
* *
@ -62,6 +133,20 @@ namespace Dawn {
*/ */
void setAudioData(AudioData *data); 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 onStart() override;
void onDispose() override; void onDispose() override;
}; };

View File

@ -22,18 +22,16 @@ namespace Dawn {
this->death = DeathPrefab::create(this); this->death = DeathPrefab::create(this);
// this->death->vnCharacter.setOpacity(0); // this->death->vnCharacter.setOpacity(0);
auto listenerItem = this->createSceneItem();
auto listener = listenerItem->addComponent<AudioListener>();
auto sourceItem = this->createSceneItem(); auto sourceItem = this->createSceneItem();
auto source = sourceItem->addComponent<AudioSource>(); auto source = sourceItem->addComponent<AudioSource>();
source->transform->setLocalPosition(glm::vec3(-1, 0, 0)); source->transform->setLocalPosition(glm::vec3(1, 0, 0));
auto data = new AudioData(); auto data = new AudioData();
data->init(); data->init();
source->setAudioData(data); source->setAudioData(data);
source->play(); source->play();
source->setLoop(true);
} }
void onSceneEnded() { void onSceneEnded() {