Really nice audio API
This commit is contained in:
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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() {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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() {
|
||||||
|
Reference in New Issue
Block a user