Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add Audio Mixer #493

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions rootex/core/audio/audio_bus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "common/common.h"

class AudioBus
{
private:
String m_BusName;
AudioBus* m_Parent = nullptr;
Vector<Ref<AudioComponent>> m_AudioComponents;
Vector<AudioBus*> m_Children;
bool m_IsMaster; // really needed?
// TODO: change volume of components when m_Volume changes
float m_Volume;

AudioBus();
AudioBus(AudioBus&) = delete;
~AudioBus() = default;

public:
void addAudioComponent(Ref<AudioComponent> cp);
void onVolumeChange(float delta);
void setParent(AudioBus* parent);
String getBusName() { return m_BusName; };
float& getBusVolume() { return m_Volume; };
};
34 changes: 33 additions & 1 deletion rootex/framework/components/audio/audio_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ AudioComponent::AudioComponent(
, m_DependencyOnBoxColliderComponent(this)
, m_DependencyOnCapsuleColliderComponent(this)
, m_DependencyOnSphereColliderComponent(this)
{
, m_AudioBus(nullptr) // get the master bus ptr => getMasterBus()
{
// By default the audio component's bus should be master
}

RigidBodyComponent* AudioComponent::getCollider()
Expand Down Expand Up @@ -125,6 +127,23 @@ void AudioComponent::setLooping(bool enabled)
m_AudioSource->setLooping(enabled);
}

void AudioComponent::setAudioBus(AudioBus* bus)
{
m_AudioBus = bus; // to be thought upon whether, using BusName here would be better or a pointer
bus->addAudioComponent(Ref<AudioComponent>(this));
}

void AudioComponent::changeVolume(float delta)
{
if (delta > 1.0f)
{
return;
WARN("Wrong volume change");
}

m_Volume = m_Volume * (1.0f - delta);
}

void AudioComponent::draw()
{
RenderSystem::GetSingleton()->submitSphere(getTransformComponent()->getAbsoluteTransform().Translation(), m_MaxDistance);
Expand Down Expand Up @@ -176,4 +195,17 @@ void AudioComponent::draw()
ImGui::DragFloat("Rolloff Factor", &m_RolloffFactor, 1.0f, 0.0f, 100.0f);
ImGui::DragFloat("Max Distance", &m_MaxDistance, 1.0f, 0.0f, 100.0f);
ImGui::DragFloat("Volume", &m_Volume, 0.01f, 0.0f, 100.0f);

// Audio mixer UI
if (ImGui::BeginCombo("Bus", AudioSystem::GetSingleton()->getAudioBuses()[0]->getBusName().c_str()))
{
for (auto& cp : AudioSystem::GetSingleton()->getAudioBuses())
{
if (ImGui::Selectable(cp->getBusName().c_str()))
{
setAudioBus(cp);
}
}
ImGui::EndCombo();
}
}
9 changes: 8 additions & 1 deletion rootex/framework/components/audio/audio_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "components/physics/box_collider_component.h"
#include "components/physics/sphere_collider_component.h"
#include "components/physics/capsule_collider_component.h"
#include "systems/audio_system.h"

class AudioBus;

class AudioComponent : public Component
{
Expand All @@ -22,6 +25,7 @@ class AudioComponent : public Component
ALfloat m_MaxDistance;
ALfloat m_Volume;
AudioSource* m_AudioSource;
AudioBus* m_AudioBus;

protected:
bool m_IsPlayOnStart;
Expand Down Expand Up @@ -61,5 +65,8 @@ class AudioComponent : public Component

bool setupData() override;
JSON::json getJSON() const;
void draw() override;
void draw() override;

void setAudioBus(AudioBus* bus);
void changeVolume(float delta);
};
140 changes: 70 additions & 70 deletions rootex/framework/components/audio/music_component.cpp
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
#include "music_component.h"

DEFINE_COMPONENT(MusicComponent);

MusicComponent::MusicComponent(Entity& owner, const JSON::json& data)
: AudioComponent(
owner,
data.value("playOnStart", false),
data.value("volume", 1.0f),
data.value("isLooping", false),
data.value("isAttenuated", false),
(AudioSource::AttenuationModel)data.value("attenuationModel", (int)AudioSource::AttenuationModel::Linear),
(ALfloat)data.value("rollOffFactor", 1.0f),
(ALfloat)data.value("referenceDistance", 1.0f),
(ALfloat)data.value("maxDistance", 100.0f))
, m_AudioFile(ResourceLoader::CreateAudioResourceFile(data.value("audio", "rootex/assets/ball.wav")))
{
}

MusicComponent::~MusicComponent()
{
m_StreamingAudioSource.reset();
}

bool MusicComponent::setupData()
{
m_StreamingAudioSource.reset();
m_StreamingAudioBuffer.reset(new StreamingAudioBuffer(m_AudioFile));
m_StreamingAudioSource.reset(new StreamingAudioSource(m_StreamingAudioBuffer));

setAudioSource(m_StreamingAudioSource.get());

return AudioComponent::setupData();
}

JSON::json MusicComponent::getJSON() const
{
JSON::json& j = AudioComponent::getJSON();

j["audio"] = m_AudioFile->getPath().string();
j["playOnStart"] = m_IsPlayOnStart;

return j;
}

void MusicComponent::setAudioFile(Ref<AudioResourceFile> audioFile)
{
m_AudioFile = audioFile;
setupData();
}

void MusicComponent::draw()
{
ImGui::Text("%s", m_AudioFile->getPath().generic_string().c_str());
ImGui::SameLine();
if (ImGui::Button("Audio File"))
{
EventManager::GetSingleton()->call(EditorEvents::EditorOpenFile, VariantVector { m_AudioFile->getPath().generic_string(), (int)m_AudioFile->getType() });
}
ImGui::SameLine();
if (ImGui::Button(ICON_ROOTEX_FOLDER_OPEN "##Select Music"))
{
if (Optional<String> result = OS::SelectFile(SupportedFiles.at(ResourceFile::Type::Audio), "game/assets/"))
{
setAudioFile(ResourceLoader::CreateAudioResourceFile(*result));
}
}

AudioComponent::draw();
}
#include "music_component.h"
DEFINE_COMPONENT(MusicComponent);
MusicComponent::MusicComponent(Entity& owner, const JSON::json& data)
: AudioComponent(
owner,
data.value("playOnStart", false),
data.value("volume", 1.0f),
data.value("isLooping", false),
data.value("isAttenuated", false),
(AudioSource::AttenuationModel)data.value("attenuationModel", (int)AudioSource::AttenuationModel::Linear),
(ALfloat)data.value("rollOffFactor", 1.0f),
(ALfloat)data.value("referenceDistance", 1.0f),
(ALfloat)data.value("maxDistance", 100.0f))
, m_AudioFile(ResourceLoader::CreateAudioResourceFile(data.value("audio", "rootex/assets/ball.wav")))
{
}
MusicComponent::~MusicComponent()
{
m_StreamingAudioSource.reset();
}
bool MusicComponent::setupData()
{
m_StreamingAudioSource.reset();
m_StreamingAudioBuffer.reset(new StreamingAudioBuffer(m_AudioFile));
m_StreamingAudioSource.reset(new StreamingAudioSource(m_StreamingAudioBuffer));
setAudioSource(m_StreamingAudioSource.get());
return AudioComponent::setupData();
}
JSON::json MusicComponent::getJSON() const
{
JSON::json& j = AudioComponent::getJSON();
j["audio"] = m_AudioFile->getPath().string();
j["playOnStart"] = m_IsPlayOnStart;
return j;
}
void MusicComponent::setAudioFile(Ref<AudioResourceFile> audioFile)
{
m_AudioFile = audioFile;
setupData();
}
void MusicComponent::draw()
{
ImGui::Text("%s", m_AudioFile->getPath().generic_string().c_str());
ImGui::SameLine();
if (ImGui::Button("Audio File"))
{
EventManager::GetSingleton()->call(EditorEvents::EditorOpenFile, VariantVector { m_AudioFile->getPath().generic_string(), (int)m_AudioFile->getType() });
}
ImGui::SameLine();
if (ImGui::Button(ICON_ROOTEX_FOLDER_OPEN "##Select Music"))
{
if (Optional<String> result = OS::SelectFile(SupportedFiles.at(ResourceFile::Type::Audio), "game/assets/"))
{
setAudioFile(ResourceLoader::CreateAudioResourceFile(*result));
}
}
AudioComponent::draw();
}
84 changes: 84 additions & 0 deletions rootex/framework/systems/audio_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,69 @@ void AudioSystem::end()
smc.getAudioSource()->stop();
}
}
void AudioSystem::addNewBus()
{
// adds a new bus to the vector and the tree
}

void AudioSystem::removeBus(AudioBus* bus)
{
// removes an audio bus from the vector and the tree
}

AudioBus::AudioBus()
: m_Volume(100.0f)
, m_BusName("Bus " + AudioSystem::GetSingleton()->getAudioBuses().size()) // naming logic to be seen
, m_Parent(nullptr) // if not the first bus, then we need to see how to assign this to the master bus in the starting
, m_IsMaster(false)
{
m_AudioComponents.clear();
m_Children.clear();
}

void AudioBus::addAudioComponent(Ref<AudioComponent> cp)
{
m_AudioComponents.push_back(cp);
}

void AudioSystem::draw()
{
System::draw();
for (int i = 0; i < m_Buses.size(); i++)
{
AudioBus* bus = m_Buses[i];
ImGui::Text(bus->getBusName().c_str());

if (ImGui::Button(ICON_ROOTEX_MINUS "##Remove Bus"))
{
removeBus(bus);
}

// volume of the bus
ImGui::DragFloat("Volume", &bus->getBusVolume(), 1.0f, 0.0f, 100.0f);

// selecting the parent
if (ImGui::BeginCombo("Parent", m_Buses[0]->getBusName().c_str()))
{
for (int j = 0; j < i; j++)
{
AudioBus* cp = m_Buses[j];
if (ImGui::Selectable(cp->getBusName().c_str()))
{
bus->setParent(cp);
}
}
ImGui::EndCombo();
}
}

if (ImGui::Button(ICON_ROOTEX_PLUS "##Add Bus"))
{
addNewBus();
}

ImGui::Text("AudioMixerSystem");
}

void AudioSystem::setListener(AudioListenerComponent* listenerComponent)
{
Expand Down Expand Up @@ -187,4 +250,25 @@ void AudioSystem::shutDown()
AudioSystem::AudioSystem()
: System("AudioSystem", UpdateOrder::Async, true)
{
m_Buses.clear();
m_Buses.push_back(nullptr); // add the master audio bus here => new AudioBus(is_Master = true)
}

void AudioBus::onVolumeChange(float delta)
{
for (auto& ac : m_AudioComponents)
{
ac->changeVolume(delta);
// the fraction of change is to be decided
}

for (auto& child : m_Children)
{
child->onVolumeChange(delta);
}
}

void AudioBus::setParent(AudioBus* parent)
{
m_Parent = parent;
}
Loading