Audio API first pass
This commit is contained in:
21
src/dawnopenal/CMakeLists.txt
Normal file
21
src/dawnopenal/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Libraries
|
||||
target_link_libraries(${DAWN_TARGET_NAME}
|
||||
PUBLIC
|
||||
OpenAL
|
||||
AudioFile
|
||||
)
|
||||
|
||||
# Includes
|
||||
target_include_directories(${DAWN_TARGET_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(scene)
|
82
src/dawnopenal/audio/AudioData.cpp
Normal file
82
src/dawnopenal/audio/AudioData.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AudioData.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
AudioData::AudioData() {
|
||||
|
||||
}
|
||||
|
||||
void AudioData::init() {
|
||||
alGenBuffers((ALsizei)1, &this->buffer);
|
||||
|
||||
// Test
|
||||
AudioFile<double> audioFile;
|
||||
audioFile.load ("C:\\sample.wav");
|
||||
audioFile.printSummary();
|
||||
|
||||
ALenum format;
|
||||
switch(audioFile.getBitDepth()) {
|
||||
case 16:
|
||||
switch(audioFile.getNumChannels()) {
|
||||
case 2:
|
||||
format = AL_FORMAT_STEREO16;
|
||||
break;
|
||||
case 1:
|
||||
format = AL_FORMAT_MONO16;
|
||||
break;
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
switch(audioFile.getNumChannels()) {
|
||||
case 2:
|
||||
format = AL_FORMAT_STEREO8;
|
||||
break;
|
||||
case 1:
|
||||
format = AL_FORMAT_MONO8;
|
||||
break;
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
|
||||
format = AL_FORMAT_MONO16;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++) {
|
||||
// for(int y = 0; y < audioFile.getNumChannels(); y++) {
|
||||
for(int y = 0; y < 1; y++) {
|
||||
double sample = audioFile.samples[y][i];
|
||||
sample = mathClamp(sample, -1., 1.);
|
||||
auto q = static_cast<int16_t> (sample * 32767.);
|
||||
|
||||
uint8_t bytes[2];
|
||||
bytes[0] = (q >> 8) & 0xFF;
|
||||
bytes[1] = q & 0xFF;
|
||||
data.push_back(bytes[1]);
|
||||
data.push_back(bytes[0]);
|
||||
}
|
||||
}
|
||||
alBufferData(buffer, format, &data[0], data.size(), audioFile.getSampleRate());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this->ready = true;
|
||||
}
|
||||
|
||||
AudioData::~AudioData() {
|
||||
if(this->ready) alDeleteBuffers((ALsizei)1, &this->buffer);
|
||||
}
|
31
src/dawnopenal/audio/AudioData.hpp
Normal file
31
src/dawnopenal/audio/AudioData.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "dawnopenal.hpp"
|
||||
#include "assert/assert.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AudioSource;
|
||||
|
||||
class AudioData {
|
||||
private:
|
||||
ALuint buffer;
|
||||
bool_t ready = false;
|
||||
ALenum format;
|
||||
|
||||
public:
|
||||
|
||||
AudioData();
|
||||
|
||||
void init();
|
||||
|
||||
~AudioData();
|
||||
|
||||
friend class AudioSource;
|
||||
};
|
||||
}
|
27
src/dawnopenal/audio/AudioManager.cpp
Normal file
27
src/dawnopenal/audio/AudioManager.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AudioManager.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
AudioManager::AudioManager(DawnGame *g) : IAudioManager(g) {
|
||||
|
||||
}
|
||||
|
||||
void AudioManager::init() {
|
||||
this->device = alcOpenDevice(nullptr);
|
||||
if(!this->device) assertUnreachable();
|
||||
|
||||
this->context = alcCreateContext(this->device, NULL);
|
||||
if(!alcMakeContextCurrent(this->context)) assertUnreachable();
|
||||
|
||||
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
||||
}
|
||||
|
||||
void AudioManager::update() {
|
||||
|
||||
}
|
22
src/dawnopenal/audio/AudioManager.hpp
Normal file
22
src/dawnopenal/audio/AudioManager.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnopenal.hpp"
|
||||
#include "audio/_AudioManager.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AudioManager : public IAudioManager {
|
||||
private:
|
||||
ALCdevice *device = nullptr;
|
||||
ALCcontext *context = nullptr;
|
||||
|
||||
public:
|
||||
AudioManager(DawnGame *game);
|
||||
|
||||
void init() override;
|
||||
void update() override;
|
||||
};
|
||||
}
|
11
src/dawnopenal/audio/CMakeLists.txt
Normal file
11
src/dawnopenal/audio/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
AudioData.cpp
|
||||
AudioManager.cpp
|
||||
)
|
9
src/dawnopenal/dawnopenal.hpp
Normal file
9
src/dawnopenal/dawnopenal.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include "AudioFile.h"
|
7
src/dawnopenal/scene/CMakeLists.txt
Normal file
7
src/dawnopenal/scene/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(components)
|
7
src/dawnopenal/scene/components/CMakeLists.txt
Normal file
7
src/dawnopenal/scene/components/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(audio)
|
33
src/dawnopenal/scene/components/audio/AudioListener.cpp
Normal file
33
src/dawnopenal/scene/components/audio/AudioListener.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AudioListener.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
AudioListener::AudioListener(SceneItem *i) : SceneItemComponent(i) {
|
||||
|
||||
}
|
||||
|
||||
void AudioListener::onStart() {
|
||||
alListener3f(AL_VELOCITY, 0, 0, 0);
|
||||
|
||||
ALfloat listenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
|
||||
alListenerfv(AL_ORIENTATION, listenerOri);
|
||||
|
||||
glm::vec3 position = this->transform->getLocalPosition();
|
||||
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
||||
|
||||
this->transform->eventTransformUpdated.addListener(this, &AudioListener::onTransformUpdate);
|
||||
}
|
||||
|
||||
void AudioListener::onDispose() {
|
||||
this->transform->eventTransformUpdated.removeListener(this, &AudioListener::onTransformUpdate);
|
||||
}
|
||||
|
||||
void AudioListener::onTransformUpdate() {
|
||||
glm::vec3 position = this->transform->getWorldPosition();
|
||||
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
||||
}
|
21
src/dawnopenal/scene/components/audio/AudioListener.hpp
Normal file
21
src/dawnopenal/scene/components/audio/AudioListener.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnopenal.hpp"
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AudioListener : public SceneItemComponent {
|
||||
private:
|
||||
void onTransformUpdate();
|
||||
|
||||
public:
|
||||
AudioListener(SceneItem *item);
|
||||
|
||||
void onStart() override;
|
||||
void onDispose() override;
|
||||
};
|
||||
}
|
90
src/dawnopenal/scene/components/audio/AudioSource.cpp
Normal file
90
src/dawnopenal/scene/components/audio/AudioSource.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AudioSource.hpp"
|
||||
#include "scene/SceneItem.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
AudioSource::AudioSource(SceneItem *i) : SceneItemComponent(i) {
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// Looping
|
||||
alSourcei(this->source, AL_LOOPING, this->loop);
|
||||
|
||||
// Source
|
||||
if(this->data != nullptr && this->data->ready) {
|
||||
alSourcei(source, AL_BUFFER, this->data->buffer);
|
||||
}
|
||||
|
||||
// Playing
|
||||
if(this->playing) alSourcePlay(this->source);
|
||||
|
||||
// Listen for events
|
||||
this->transform->eventTransformUpdated.addListener(this, &AudioSource::onTransformUpdate);
|
||||
|
||||
this->ready = true;
|
||||
}
|
||||
|
||||
bool_t AudioSource::isLooping() {
|
||||
return this->loop;
|
||||
}
|
||||
|
||||
void AudioSource::setLoop(bool_t loop) {
|
||||
this->loop = loop;
|
||||
if(this->ready) alSourcei(this->source, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
bool_t AudioSource::isPlaying() {
|
||||
return this->playing;
|
||||
}
|
||||
|
||||
void AudioSource::play() {
|
||||
this->playing = true;
|
||||
if(this->ready && data != nullptr && data->ready) {
|
||||
alSourcePlay(this->source);
|
||||
}
|
||||
}
|
||||
|
||||
AudioData * AudioSource::getAudioData() {
|
||||
return this->data;
|
||||
}
|
||||
|
||||
void AudioSource::setAudioData(AudioData *data) {
|
||||
this->data = data;
|
||||
if(this->ready && data != nullptr && data->ready) {
|
||||
alSourcei(source, AL_BUFFER, data->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::onDispose() {
|
||||
this->transform->eventTransformUpdated.removeListener(this, &AudioSource::onTransformUpdate);
|
||||
|
||||
this->ready = false;
|
||||
alDeleteSources((ALuint)1, &this->source);
|
||||
}
|
||||
|
||||
void AudioSource::onTransformUpdate() {
|
||||
glm::vec3 position = this->transform->getWorldPosition();
|
||||
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
|
||||
}
|
68
src/dawnopenal/scene/components/audio/AudioSource.hpp
Normal file
68
src/dawnopenal/scene/components/audio/AudioSource.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnopenal.hpp"
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "audio/AudioData.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AudioSource : public SceneItemComponent {
|
||||
private:
|
||||
ALuint source;
|
||||
bool_t ready = false;
|
||||
|
||||
// Settings
|
||||
bool_t loop = false;
|
||||
bool_t playing = false;
|
||||
int32_t layer = 0;
|
||||
AudioData *data = nullptr;
|
||||
|
||||
void onTransformUpdate();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an Audio Source item component.
|
||||
*
|
||||
* @param item SceneItem that this audio source is attached to.
|
||||
*/
|
||||
AudioSource(SceneItem *item);
|
||||
|
||||
/**
|
||||
* Returns whether or not the audio source is set to loop or not.
|
||||
*
|
||||
* @return True if the source is looping otherwise false.
|
||||
*/
|
||||
bool_t isLooping();
|
||||
|
||||
/**
|
||||
* Sets whether the audio source should loop or not.
|
||||
*
|
||||
* @param loop Loop or not.
|
||||
*/
|
||||
void setLoop(bool_t loop);
|
||||
|
||||
bool_t isPlaying();
|
||||
void play();
|
||||
|
||||
/**
|
||||
* Returns the current audio data for this source.
|
||||
*
|
||||
* @return Audio data that is atached to this source.
|
||||
*/
|
||||
AudioData * getAudioData();
|
||||
|
||||
/**
|
||||
* Sets the audio data for this source. Currently switching between the
|
||||
* audio data during playback may have undefined behavior.
|
||||
*
|
||||
* @param data Data to set.
|
||||
*/
|
||||
void setAudioData(AudioData *data);
|
||||
|
||||
void onStart() override;
|
||||
void onDispose() override;
|
||||
};
|
||||
}
|
11
src/dawnopenal/scene/components/audio/CMakeLists.txt
Normal file
11
src/dawnopenal/scene/components/audio/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
AudioListener.cpp
|
||||
AudioSource.cpp
|
||||
)
|
Reference in New Issue
Block a user