Added simple audio visualiser and componenet/Engine core systems
This commit is contained in:
parent
31d9176b0d
commit
dbd0ad28d2
76
imgui.ini
76
imgui.ini
@ -14,10 +14,10 @@ Size=1280,701
|
||||
Collapsed=0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=831,19
|
||||
Size=449,439
|
||||
Pos=991,19
|
||||
Size=289,701
|
||||
Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
DockId=0x00000017,0
|
||||
|
||||
[Window][Scene Tree]
|
||||
Pos=0,19
|
||||
@ -27,7 +27,7 @@ DockId=0x00000003,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=344,19
|
||||
Size=485,390
|
||||
Size=645,390
|
||||
Collapsed=0
|
||||
DockId=0x00000007,0
|
||||
|
||||
@ -36,16 +36,16 @@ Size=1280,19
|
||||
Collapsed=0
|
||||
|
||||
[Window][Performance Info]
|
||||
Pos=344,411
|
||||
Size=485,309
|
||||
Pos=978,592
|
||||
Size=302,128
|
||||
Collapsed=0
|
||||
DockId=0x00000008,2
|
||||
DockId=0x00000011,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=344,411
|
||||
Size=485,309
|
||||
Size=541,139
|
||||
Collapsed=0
|
||||
DockId=0x00000008,0
|
||||
DockId=0x00000013,0
|
||||
|
||||
[Window][Tilemap Editor]
|
||||
Pos=265,19
|
||||
@ -54,34 +54,34 @@ Collapsed=0
|
||||
DockId=0x00000007,1
|
||||
|
||||
[Window][Profiler]
|
||||
Pos=344,411
|
||||
Size=485,309
|
||||
Pos=344,552
|
||||
Size=541,168
|
||||
Collapsed=0
|
||||
DockId=0x00000008,3
|
||||
DockId=0x00000014,0
|
||||
|
||||
[Window][Profiler Timeline]
|
||||
Pos=265,69
|
||||
Size=623,651
|
||||
Collapsed=0
|
||||
DockId=0x00000008,1
|
||||
DockId=0x00000013,1
|
||||
|
||||
[Window][Profiler (Unity Style)]
|
||||
Pos=265,430
|
||||
Size=623,290
|
||||
Collapsed=0
|
||||
DockId=0x00000008,1
|
||||
DockId=0x00000013,1
|
||||
|
||||
[Window][Profiler Timeline View]
|
||||
Pos=265,526
|
||||
Size=1263,651
|
||||
Collapsed=0
|
||||
DockId=0x00000008,1
|
||||
DockId=0x00000013,1
|
||||
|
||||
[Window][Color Correction]
|
||||
Pos=344,411
|
||||
Size=485,309
|
||||
Pos=1131,592
|
||||
Size=149,128
|
||||
Collapsed=0
|
||||
DockId=0x00000008,1
|
||||
DockId=0x00000012,0
|
||||
|
||||
[Window][Asset Browser]
|
||||
Pos=0,369
|
||||
@ -107,25 +107,47 @@ Collapsed=0
|
||||
DockId=0x0000000C,0
|
||||
|
||||
[Window][Playing Audio]
|
||||
Pos=831,460
|
||||
Size=449,260
|
||||
Pos=978,460
|
||||
Size=302,260
|
||||
Collapsed=0
|
||||
DockId=0x0000000E,0
|
||||
DockId=0x0000000F,0
|
||||
|
||||
[Window][Audio Output]
|
||||
Pos=887,411
|
||||
Size=102,309
|
||||
Collapsed=0
|
||||
DockId=0x00000016,0
|
||||
|
||||
[Window][Master Bus]
|
||||
Pos=1003,570
|
||||
Size=277,150
|
||||
Collapsed=0
|
||||
DockId=0x00000018,0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=829,1158 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=989,1158 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=342,701 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,575 HiddenTabBar=1 Selected=0x12EF0F59
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,581 HiddenTabBar=1 Selected=0x36AF052B
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=485,701 Split=Y Selected=0xC450F867
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=645,701 Split=Y Selected=0xC450F867
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,847 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867
|
||||
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,309 Selected=0x9B5D3198
|
||||
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=449,1158 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,309 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000015 Parent=0x00000008 SizeRef=541,172 Split=Y Selected=0xEA83D666
|
||||
DockNode ID=0x00000013 Parent=0x00000015 SizeRef=553,139 HiddenTabBar=1 Selected=0xEA83D666
|
||||
DockNode ID=0x00000014 Parent=0x00000015 SizeRef=553,168 HiddenTabBar=1 Selected=0x9B5D3198
|
||||
DockNode ID=0x00000016 Parent=0x00000008 SizeRef=102,172 HiddenTabBar=1 Selected=0x56009A08
|
||||
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=289,1158 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000009 Parent=0x00000006 SizeRef=449,488 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=449,556 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=449,439 HiddenTabBar=1 Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=449,260 HiddenTabBar=1 Selected=0x9D7E7171
|
||||
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=449,439 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000017 Parent=0x0000000D SizeRef=277,549 HiddenTabBar=1 Selected=0x36DC96AB
|
||||
DockNode ID=0x00000018 Parent=0x0000000D SizeRef=277,150 Selected=0x96A8354B
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=449,260 Split=Y Selected=0x9D7E7171
|
||||
DockNode ID=0x0000000F Parent=0x0000000E SizeRef=302,215 HiddenTabBar=1 Selected=0x9D7E7171
|
||||
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=302,213 Split=X Selected=0x3FC1A724
|
||||
DockNode ID=0x00000011 Parent=0x00000010 SizeRef=151,213 HiddenTabBar=1 Selected=0x3FC1A724
|
||||
DockNode ID=0x00000012 Parent=0x00000010 SizeRef=149,213 HiddenTabBar=1 Selected=0xA873C17F
|
||||
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=449,143 HiddenTabBar=1 Selected=0xB6C74292
|
||||
DockNode ID=0x0000000A Parent=0x00000006 SizeRef=449,211 HiddenTabBar=1 Selected=0xD83E5DD3
|
||||
|
||||
|
@ -6,6 +6,8 @@ src_dirs:
|
||||
- src/vendor/imgui
|
||||
- src/vendor/box2d
|
||||
- src/vendor/xxhash
|
||||
- src/vendor/miniaudio
|
||||
|
||||
|
||||
|
||||
# Include directories (-I)
|
||||
|
@ -0,0 +1,3 @@
|
||||
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\editor\windows\AudioInfo.cpp -o src\build\editor\windows\AudioInfo.o
|
||||
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\AudioPlayerComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\audio\AudioEngine.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\LoadingWindow.o src\build\core\utils\Logging.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\AudioInfo.o src\build\editor\windows\Inspector.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o src\build\xxhash.o src\build\miniaudio.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
|
||||
[RUN] Executed app.exe successfully.
|
53
src/assets/scenes/audio_testing.cene
Normal file
53
src/assets/scenes/audio_testing.cene
Normal file
@ -0,0 +1,53 @@
|
||||
engine_version: 0.1.0
|
||||
scene_name: audio_testing
|
||||
scene_hash: 2789578d9c2a7814ff6e4c0ef38fcfb5ae09fb6b1418f89557e43c6649010ed4
|
||||
format_version: 1
|
||||
objects:
|
||||
- name: Hello, Create
|
||||
uid: f4ee58087d1c475784f951128c27d7c2
|
||||
id: 0
|
||||
position: [0, 0]
|
||||
rotation: 0
|
||||
layer: 0
|
||||
visable: true
|
||||
components:
|
||||
- type: AudioPlayerComponent
|
||||
uaid: 2
|
||||
volume: 0.158999994
|
||||
loop: false
|
||||
children: []
|
||||
- name: NewObject
|
||||
uid: 2125b52bb74344d680ad4332671c78c2
|
||||
id: 1
|
||||
position: [0, 0]
|
||||
rotation: 0
|
||||
layer: 0
|
||||
visable: true
|
||||
components:
|
||||
- type: AudioPlayerComponent
|
||||
uaid: 1
|
||||
volume: 0.0419999994
|
||||
loop: false
|
||||
children: []
|
||||
color_correction:
|
||||
brightness: 1
|
||||
saturation: 1
|
||||
gamma: 1
|
||||
bloom: true
|
||||
intensity: 1.20000005
|
||||
threshold: 1
|
||||
Assets:
|
||||
- uaid: 2
|
||||
path: C:\Users\spenc\Music\simple-notification-152054.wav
|
||||
filename: simple-notification-152054.wav
|
||||
filetype: wav
|
||||
type: 1
|
||||
hash: 0f5adca8b95e7494
|
||||
lastModified: 1745952999
|
||||
- uaid: 1
|
||||
path: C:\Users\spenc\Music\creative-technology-showreel-241274.mp3
|
||||
filename: creative-technology-showreel-241274.mp3
|
||||
filetype: mp3
|
||||
type: 1
|
||||
hash: d7f8e8b2954d438f
|
||||
lastModified: 1730076792
|
@ -1,100 +1,77 @@
|
||||
#include "AudioPlayerComponent.h"
|
||||
#include "../core/utils/Logging.h"
|
||||
#include "../core/utils/AssetManager.h"
|
||||
#include "../core/audio/AudioEngine.h"
|
||||
|
||||
AudioPlayerComponent::AudioPlayerComponent(Object* owner)
|
||||
: Component(owner) {}
|
||||
: Component(owner)
|
||||
{}
|
||||
|
||||
AudioPlayerComponent::~AudioPlayerComponent()
|
||||
{
|
||||
if (m_OwnsSound && m_Sound)
|
||||
{
|
||||
ma_sound_uninit(m_Sound);
|
||||
delete m_Sound;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::SetAudio(uint64_t uaid)
|
||||
{
|
||||
Stop();
|
||||
void AudioPlayerComponent::SetAudio(uint64_t uaid) {
|
||||
m_UAID = uaid;
|
||||
|
||||
const auto* asset = dynamic_cast<const AudioAssetInfo*>(AssetManager::GetAssetByID(uaid));
|
||||
if (!asset || !asset->loaded)
|
||||
{
|
||||
Logger::LogWarning("AudioPlayerComponent: Asset not found or not loaded (UAID: %llu)", uaid);
|
||||
m_Sound = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Sound = asset->sound;
|
||||
m_OwnsSound = false;
|
||||
|
||||
ma_sound_set_volume(m_Sound, volume);
|
||||
ma_sound_set_looping(m_Sound, loop ? MA_TRUE : MA_FALSE);
|
||||
void AudioPlayerComponent::Play() {
|
||||
if (m_UAID == 0) return;
|
||||
AudioEngine::Play(m_UAID, loop);
|
||||
AudioEngine::SetVolume(m_UAID, volume); // you’ll need to add this helper
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::Play()
|
||||
{
|
||||
if (m_Sound) ma_sound_start(m_Sound);
|
||||
void AudioPlayerComponent::Pause() {
|
||||
if (m_UAID == 0) return;
|
||||
AudioEngine::Stop(m_UAID);
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::Pause()
|
||||
{
|
||||
if (m_Sound) ma_sound_stop(m_Sound);
|
||||
void AudioPlayerComponent::Stop() {
|
||||
if (m_UAID == 0) return;
|
||||
AudioEngine::Stop(m_UAID);
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::Stop()
|
||||
{
|
||||
if (m_Sound)
|
||||
{
|
||||
ma_sound_stop(m_Sound);
|
||||
ma_sound_seek_to_pcm_frame(m_Sound, 0);
|
||||
void AudioPlayerComponent::Update() {
|
||||
// drive the engine’s per-frame update
|
||||
AudioEngine::Update();
|
||||
|
||||
// now you can, if you like, pull back the current time or VU data
|
||||
// for your own logic/UI. E.g.:
|
||||
auto& map = AudioEngine::GetPlayingInfoMap();
|
||||
auto it = map.find(m_UAID);
|
||||
if (it != map.end()) {
|
||||
const auto& info = it->second;
|
||||
// info.currentTime, info.totalTime, info.vuLeft, info.vuRight ...
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::SetLooping(bool value)
|
||||
{
|
||||
|
||||
|
||||
void AudioPlayerComponent::SetLooping(bool value) {
|
||||
loop = value;
|
||||
if (m_Sound) ma_sound_set_looping(m_Sound, value ? MA_TRUE : MA_FALSE);
|
||||
if (m_UAID != 0) {
|
||||
AudioEngine::SetLooping(m_UAID, value);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::SetVolume(float vol)
|
||||
{
|
||||
void AudioPlayerComponent::SetVolume(float vol) {
|
||||
volume = vol;
|
||||
if (m_Sound) ma_sound_set_volume(m_Sound, vol);
|
||||
if (m_UAID != 0) {
|
||||
AudioEngine::SetVolume(m_UAID, vol);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioPlayerComponent::IsPlaying() const
|
||||
{
|
||||
return m_Sound && ma_sound_is_playing(m_Sound);
|
||||
}
|
||||
|
||||
std::string AudioPlayerComponent::GetName() const
|
||||
{
|
||||
return "AudioPlayerComponent";
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::Save(YAML::Emitter& out) const
|
||||
{
|
||||
|
||||
void AudioPlayerComponent::Save(YAML::Emitter& out) const {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "type" << YAML::Value << GetName();
|
||||
out << YAML::Key << "uaid" << YAML::Value << m_UAID;
|
||||
out << YAML::Key << "volume" << YAML::Value << volume;
|
||||
out << YAML::Key << "loop" << YAML::Value << loop;
|
||||
out << YAML::EndMap;
|
||||
|
||||
}
|
||||
|
||||
void AudioPlayerComponent::Load(const YAML::Node& node)
|
||||
{
|
||||
if (node["uaid"])
|
||||
{
|
||||
m_UAID = node["uaid"].as<uint64_t>();
|
||||
SetAudio(m_UAID);
|
||||
}
|
||||
if (node["volume"])
|
||||
SetVolume(node["volume"].as<float>());
|
||||
if (node["loop"])
|
||||
SetLooping(node["loop"].as<bool>());
|
||||
void AudioPlayerComponent::Load(const YAML::Node& node) {
|
||||
if (node["uaid"]) m_UAID = node["uaid"].as<uint64_t>();
|
||||
if (node["volume"]) volume = node["volume"].as<float>();
|
||||
if (node["loop"]) loop = node["loop"].as<bool>();
|
||||
// don’t auto-play on load
|
||||
}
|
||||
|
@ -1,37 +1,36 @@
|
||||
#pragma once
|
||||
#include "Component.h"
|
||||
#include "../core/audio/AudioEngine.h"
|
||||
#include "../core/utils/AssetManager.h"
|
||||
#include <string>
|
||||
|
||||
class AudioPlayerComponent : public Component
|
||||
{
|
||||
#include "Component.h"
|
||||
#include <cstdint>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
class AudioPlayerComponent : public Component {
|
||||
public:
|
||||
AudioPlayerComponent(Object* owner);
|
||||
~AudioPlayerComponent();
|
||||
~AudioPlayerComponent() override {}
|
||||
|
||||
void SetAudio(uint64_t uaid);
|
||||
void Play();
|
||||
void Pause();
|
||||
void Stop();
|
||||
|
||||
void SetLooping(bool loop);
|
||||
void SetLooping(bool value);
|
||||
void SetVolume(float vol);
|
||||
|
||||
bool IsPlaying() const;
|
||||
|
||||
// Serialization
|
||||
std::string GetName() const override;
|
||||
void Save(YAML::Emitter& out) const override;
|
||||
void Load(const YAML::Node& node) override;
|
||||
|
||||
uint64_t GetUAID() const { return m_UAID; }
|
||||
|
||||
private:
|
||||
ma_sound* m_Sound = nullptr;
|
||||
uint64_t m_UAID = 0;
|
||||
bool m_OwnsSound = false;
|
||||
void Update();
|
||||
|
||||
// No longer used:
|
||||
bool IsPlaying() const { return false; }
|
||||
std::string GetName() const override { return "AudioPlayerComponent"; }
|
||||
|
||||
void Save(YAML::Emitter& out) const override;
|
||||
void Load(const YAML::Node& node) override;
|
||||
|
||||
private:
|
||||
uint64_t m_UAID = 0;
|
||||
float volume = 1.0f;
|
||||
bool loop = false;
|
||||
};
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "editor/windows/AssetBrowser.h"
|
||||
#include "editor/windows/Inspector.h"
|
||||
#include "editor/windows/AudioInfo.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
@ -347,6 +348,11 @@ void ShowProfilerTimeline()
|
||||
|
||||
void Engine::ShowDebugOverlay(float deltaTime)
|
||||
{
|
||||
if (!g_engineConfig.settings.show_performance_window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// === Performance Window ===
|
||||
static std::vector<float> fpsHistory;
|
||||
static const int maxFpsHistory = 100;
|
||||
@ -516,6 +522,8 @@ void Engine::Init()
|
||||
|
||||
AudioEngine::Init();
|
||||
|
||||
AssetManager::LoadAssetAsync("C:\\Users\\spenc\\Music\\creative-technology-showreel-241274.mp3", AssetType::Audio);
|
||||
|
||||
Logger::LogVerbose("Resverving Objects");
|
||||
|
||||
// These values were AI Generated.
|
||||
@ -539,42 +547,6 @@ core::types::Vec2 ScreenToWorld(const core::types::Vec2 &screenPos, const core::
|
||||
|
||||
|
||||
|
||||
void DrawAudioPlayingList()
|
||||
{
|
||||
ImGui::Begin("Playing Audio");
|
||||
|
||||
std::vector<uint64_t> toStop;
|
||||
|
||||
for (const auto& [uaid, psound] : AudioEngine::GetPlayingSounds())
|
||||
{
|
||||
ImGui::Text("%s", psound.name.c_str());
|
||||
|
||||
if (psound.totalTime > 0.0)
|
||||
{
|
||||
float progress = static_cast<float>(psound.currentTime / psound.totalTime);
|
||||
ImGui::ProgressBar(progress, ImVec2(-1.0f, 6.0f));
|
||||
}
|
||||
|
||||
ImGui::Text("Time: %.2f / %.2f sec", psound.currentTime, psound.totalTime);
|
||||
|
||||
if (ImGui::Button(("Stop##" + std::to_string(uaid)).c_str()))
|
||||
{
|
||||
toStop.push_back(uaid);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
for (uint64_t id : toStop)
|
||||
AudioEngine::Stop(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom)
|
||||
{
|
||||
|
||||
@ -752,6 +724,9 @@ void Engine::Run()
|
||||
ImGui::Checkbox("Color Correction", &g_engineConfig.settings.show_color_correction_window);
|
||||
ImGui::Checkbox("Profiler", &g_engineConfig.settings.show_profiler_window);
|
||||
ImGui::Checkbox("Assets", &g_engineConfig.settings.show_asset_window);
|
||||
ImGui::Checkbox("Performance Info", &g_engineConfig.settings.show_performance_window);
|
||||
ImGui::Checkbox("Audio Viewer", &g_engineConfig.settings.show_audio_window);
|
||||
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@ -779,6 +754,8 @@ void Engine::Run()
|
||||
|
||||
ShowAssetBrowser();
|
||||
DrawAudioPlayingList();
|
||||
|
||||
|
||||
{
|
||||
PROFILE_ENGINE_SCOPE("Engine::DrawSceneTree");
|
||||
|
||||
|
@ -1,96 +1,207 @@
|
||||
#define MA_ENABLE_MP3
|
||||
#define MA_ENABLE_WAV
|
||||
#define MA_ENABLE_FLAC
|
||||
#define MA_ENABLE_VORBIS
|
||||
#define MA_IMPLEMENTATION
|
||||
#include "AudioEngine.h"
|
||||
#include "../utils/AssetManager.h"
|
||||
#include "../utils/Logging.h"
|
||||
#include <iostream>
|
||||
|
||||
// Static member definitions
|
||||
ma_engine AudioEngine::s_Engine;
|
||||
std::unordered_map<uint64_t, ma_sound*> AudioEngine::s_SoundMap;
|
||||
std::unordered_map<uint64_t, PlayingInfo> AudioEngine::s_PlayingInfoMap;
|
||||
|
||||
|
||||
std::vector<float> AudioEngine::s_MasterVU;
|
||||
|
||||
ma_engine AudioEngine::s_Engine{};
|
||||
std::unordered_map<uint64_t, PlayingSound> AudioEngine::s_PlayingSounds;
|
||||
|
||||
bool AudioEngine::Init() {
|
||||
if (ma_engine_init(nullptr, &s_Engine) != MA_SUCCESS) {
|
||||
Logger::LogError("Failed to start AudioCore");
|
||||
ma_engine_config config = ma_engine_config_init();
|
||||
config.onProcess = AudioEngine::EngineProcessCallback;
|
||||
config.pProcessUserData = nullptr;
|
||||
|
||||
ma_result r = ma_engine_init(&config, &s_Engine);
|
||||
if (r != MA_SUCCESS) {
|
||||
Logger::LogError("AudioEngine: ma_engine_init failed (%d)", r);
|
||||
return false;
|
||||
}
|
||||
Logger::LogVerbose("AudioCore initialized successfully.");
|
||||
|
||||
Logger::LogVerbose("AudioEngine initialized with master-output callback");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void AudioEngine::Shutdown() {
|
||||
for (auto& [_, s] : s_PlayingSounds)
|
||||
s.Stop();
|
||||
s_PlayingSounds.clear();
|
||||
// Uninit & delete every sound
|
||||
for (auto& kv : s_SoundMap) {
|
||||
ma_sound_uninit(kv.second);
|
||||
delete kv.second;
|
||||
}
|
||||
s_SoundMap.clear();
|
||||
s_PlayingInfoMap.clear();
|
||||
ma_engine_uninit(&s_Engine);
|
||||
}
|
||||
|
||||
void AudioEngine::Play(uint64_t uaid, bool loop) {
|
||||
if (s_PlayingSounds.find(uaid) == s_PlayingSounds.end()) {
|
||||
const auto* asset = AssetManager::GetAssetByID(uaid);
|
||||
// 1) Tear down existing instance (if any)
|
||||
Cleanup(uaid);
|
||||
|
||||
// 2) Fetch and validate asset
|
||||
const AssetInfo* asset = AssetManager::GetAssetByID(uaid);
|
||||
if (!asset || !asset->loaded || asset->type != AssetType::Audio) {
|
||||
Logger::LogError("[AudioEngine] Invalid or unloaded audio asset: %llu", uaid);
|
||||
Logger::LogError("AudioEngine::Play invalid asset %llu", uaid);
|
||||
return;
|
||||
}
|
||||
|
||||
ma_sound sound;
|
||||
if (ma_sound_init_from_file(&s_Engine, asset->path.c_str(), 0, nullptr, nullptr, &sound) != MA_SUCCESS) {
|
||||
Logger::LogError("[AudioEngine] Failed to load sound: %s", asset->path.c_str());
|
||||
// 3) Heap-allocate and init the sound from file
|
||||
ma_sound* sound = new ma_sound;
|
||||
if (ma_sound_init_from_file(
|
||||
&s_Engine,
|
||||
asset->path.c_str(),
|
||||
/*flags=*/0,
|
||||
/*pGroup=*/nullptr,
|
||||
/*pFence=*/nullptr,
|
||||
sound
|
||||
) != MA_SUCCESS)
|
||||
{
|
||||
Logger::LogError("AudioEngine::Play failed to load '%s'", asset->path.c_str());
|
||||
delete sound;
|
||||
return;
|
||||
}
|
||||
|
||||
ma_sound_set_looping(&sound, loop);
|
||||
// 4) Store and start playback
|
||||
s_SoundMap[uaid] = sound;
|
||||
ma_sound_set_looping(sound, loop ? MA_TRUE : MA_FALSE);
|
||||
ma_sound_start(sound);
|
||||
|
||||
ma_uint64 totalFrames = 0;
|
||||
ma_sound_get_length_in_pcm_frames(&sound, &totalFrames);
|
||||
ma_uint32 sampleRate = ma_engine_get_sample_rate(&s_Engine);
|
||||
double totalSeconds = sampleRate > 0 ? double(totalFrames) / sampleRate : 0.0;
|
||||
// 5) Compute totalTime
|
||||
ma_uint64 frames = 0;
|
||||
ma_sound_get_length_in_pcm_frames(sound, &frames);
|
||||
double sampleRate = ma_engine_get_sample_rate(&s_Engine);
|
||||
|
||||
PlayingSound ps{ uaid, asset->filename, sound, 0.0, totalSeconds };
|
||||
s_PlayingSounds[uaid] = ps;
|
||||
// 6) Push PlayingInfo
|
||||
PlayingInfo info;
|
||||
info.uaid = uaid;
|
||||
info.name = asset->filename;
|
||||
info.currentTime= 0.0;
|
||||
info.totalTime = double(frames) / sampleRate;
|
||||
info.looping = loop;
|
||||
info.hasStarted = false;
|
||||
info.sound = sound;
|
||||
|
||||
ma_sound_start(&s_PlayingSounds[uaid].sound);
|
||||
} else {
|
||||
auto& s = s_PlayingSounds[uaid];
|
||||
ma_sound_set_looping(&s.sound, loop);
|
||||
ma_sound_start(&s.sound);
|
||||
}
|
||||
s_PlayingInfoMap[uaid] = info;
|
||||
}
|
||||
|
||||
void AudioEngine::Stop(uint64_t uaid) {
|
||||
auto it = s_PlayingSounds.find(uaid);
|
||||
if (it != s_PlayingSounds.end()) {
|
||||
it->second.Stop();
|
||||
s_PlayingSounds.erase(it);
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_stop(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::StopAll() {
|
||||
for (auto& [_, s] : s_PlayingSounds)
|
||||
s.Stop();
|
||||
s_PlayingSounds.clear();
|
||||
for (auto& kv : s_SoundMap) {
|
||||
ma_sound_stop(kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::Unload(uint64_t uaid) {
|
||||
Stop(uaid);
|
||||
Cleanup(uaid);
|
||||
}
|
||||
|
||||
void AudioEngine::Update() {
|
||||
for (auto it = s_PlayingSounds.begin(); it != s_PlayingSounds.end();) {
|
||||
if (!ma_sound_is_playing(&it->second.sound)) {
|
||||
it->second.Stop();
|
||||
it = s_PlayingSounds.erase(it);
|
||||
|
||||
|
||||
|
||||
void AudioEngine::CleanupSound(uint64_t uaid)
|
||||
{
|
||||
auto itSound = s_SoundMap.find(uaid);
|
||||
if (itSound != s_SoundMap.end()) {
|
||||
ma_sound_uninit(itSound->second);
|
||||
delete itSound->second;
|
||||
s_SoundMap.erase(itSound);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AudioEngine::Update()
|
||||
{
|
||||
for (auto it = s_PlayingInfoMap.begin(); it != s_PlayingInfoMap.end(); )
|
||||
{
|
||||
uint64_t uaid = it->first;
|
||||
PlayingInfo &info = it->second;
|
||||
ma_sound* s = info.sound;
|
||||
|
||||
bool shouldErase = (!s) ||
|
||||
(!info.looping && info.hasStarted && !ma_sound_is_playing(s));
|
||||
|
||||
if (shouldErase) {
|
||||
CleanupSound(uaid);
|
||||
|
||||
it = s_PlayingInfoMap.erase(it);
|
||||
} else {
|
||||
ma_uint64 cursorFrames = 0;
|
||||
ma_sound_get_cursor_in_pcm_frames(&it->second.sound, &cursorFrames);
|
||||
ma_uint32 sampleRate = ma_engine_get_sample_rate(&s_Engine);
|
||||
it->second.currentTime = sampleRate > 0 ? static_cast<double>(cursorFrames) / sampleRate : 0.0;
|
||||
|
||||
if (!info.hasStarted && ma_sound_is_playing(s)) {
|
||||
info.hasStarted = true;
|
||||
}
|
||||
|
||||
ma_uint64 cursor = 0;
|
||||
if (ma_sound_get_cursor_in_pcm_frames(s, &cursor) == MA_SUCCESS) {
|
||||
info.currentTime = double(cursor) / ma_engine_get_sample_rate(&s_Engine);
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::unordered_map<uint64_t, PlayingSound>& AudioEngine::GetPlayingSounds() {
|
||||
return s_PlayingSounds;
|
||||
|
||||
void AudioEngine::SetVolume(uint64_t uaid, float v) {
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_set_volume(it->second, v);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::SetLooping(uint64_t uaid, bool loop) {
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_set_looping(it->second, loop ? MA_TRUE : MA_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::Cleanup(uint64_t uaid) {
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_uninit(it->second);
|
||||
delete it->second;
|
||||
s_SoundMap.erase(it);
|
||||
}
|
||||
s_PlayingInfoMap.erase(uaid);
|
||||
}
|
||||
|
||||
const std::unordered_map<uint64_t, PlayingInfo>& AudioEngine::GetPlayingInfoMap() {
|
||||
return s_PlayingInfoMap;
|
||||
}
|
||||
|
||||
|
||||
void AudioEngine::EngineProcessCallback(
|
||||
void* /*pUserData*/,
|
||||
float* pFramesOut,
|
||||
ma_uint64 frameCount)
|
||||
{
|
||||
// Fetch the playback device and its channel count
|
||||
ma_device* pDevice = ma_engine_get_device(&s_Engine);
|
||||
uint32_t channels = pDevice->playback.channels;
|
||||
|
||||
// Ensure our master VU vector matches the channel count
|
||||
s_MasterVU.assign(channels, 0.0f);
|
||||
|
||||
// Compute peak per channel
|
||||
for (ma_uint64 i = 0; i < frameCount; ++i) {
|
||||
for (uint32_t ch = 0; ch < channels; ++ch) {
|
||||
float v = fabsf(pFramesOut[i * channels + ch]);
|
||||
if (v > s_MasterVU[ch]) {
|
||||
s_MasterVU[ch] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const std::vector<float>& AudioEngine::GetMasterVU()
|
||||
{
|
||||
return s_MasterVU;
|
||||
}
|
||||
|
@ -1,37 +1,59 @@
|
||||
// AudioEngine.h
|
||||
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "miniaudio.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "../utils/AssetManager.h"
|
||||
#include "../utils/Logging.h"
|
||||
|
||||
struct PlayingSound {
|
||||
struct PlayingInfo
|
||||
{
|
||||
uint64_t uaid;
|
||||
std::string name;
|
||||
ma_sound sound;
|
||||
double currentTime = 0.0;
|
||||
double totalTime = 0.0;
|
||||
|
||||
void Stop() {
|
||||
ma_sound_stop(&sound);
|
||||
ma_sound_uninit(&sound);
|
||||
}
|
||||
bool looping = false;
|
||||
bool hasStarted = false;
|
||||
ma_sound *sound = nullptr;
|
||||
float vuLeft = 0.0f;
|
||||
float vuRight = 0.0f;
|
||||
};
|
||||
|
||||
class AudioEngine {
|
||||
class AudioEngine
|
||||
{
|
||||
public:
|
||||
static bool Init();
|
||||
static void Shutdown();
|
||||
|
||||
static void Play(uint64_t uaid, bool loop = false);
|
||||
static void Stop(uint64_t uaid);
|
||||
static void StopAll();
|
||||
static void Unload(uint64_t uaid);
|
||||
static void Update();
|
||||
static void SetVolume(uint64_t uaid, float volume);
|
||||
static void SetLooping(uint64_t uaid, bool loop);
|
||||
|
||||
static ma_engine* GetEngine() { return &s_Engine; }
|
||||
static const std::unordered_map<uint64_t, PlayingSound>& GetPlayingSounds();
|
||||
// Now returns a per-channel master peak vector
|
||||
static const std::vector<float> &GetMasterVU();
|
||||
|
||||
static const std::unordered_map<uint64_t, PlayingInfo> &GetPlayingInfoMap();
|
||||
|
||||
private:
|
||||
static ma_engine s_Engine;
|
||||
static std::unordered_map<uint64_t, PlayingSound> s_PlayingSounds;
|
||||
static std::unordered_map<uint64_t, ma_sound *> s_SoundMap;
|
||||
static std::unordered_map<uint64_t, PlayingInfo> s_PlayingInfoMap;
|
||||
|
||||
// Per-channel master peaks
|
||||
static std::vector<float> s_MasterVU;
|
||||
|
||||
static void CleanupSound(uint64_t uaid);
|
||||
|
||||
static void EngineProcessCallback(
|
||||
void *pUserData,
|
||||
float *pFramesOut,
|
||||
ma_uint64 frameCount);
|
||||
|
||||
static void Cleanup(uint64_t uaid);
|
||||
};
|
||||
|
@ -10,7 +10,10 @@
|
||||
USER_SETTING(lighting_enabled, bool, false) \
|
||||
USER_SETTING(profile_deep, bool, false) \
|
||||
USER_SETTING(show_asset_window, bool, false) \
|
||||
USER_SETTING(profile_gpu, bool, false)
|
||||
USER_SETTING(profile_gpu, bool, false) \
|
||||
USER_SETTING(show_performance_window, bool, false) \
|
||||
USER_SETTING(show_audio_window, bool, false)
|
||||
|
||||
|
||||
|
||||
struct UserSettings {
|
||||
|
113
src/src/editor/windows/AudioInfo.cpp
Normal file
113
src/src/editor/windows/AudioInfo.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
// AudioInfo.cpp
|
||||
#include "AudioInfo.h"
|
||||
#include "../../core/utils/EngineConfig.h"
|
||||
#include <imgui.h>
|
||||
#include "../../core/audio/AudioEngine.h"
|
||||
#include "../../core/utils/Profiler.h"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
void DrawAudioPlayingList()
|
||||
{
|
||||
PROFILE_ENGINE_SCOPE("Engine::DrawAudioPlayingList");
|
||||
if (!g_engineConfig.settings.show_audio_window)
|
||||
return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(240, 180), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Audio Output");
|
||||
|
||||
const auto& masterVU = AudioEngine::GetMasterVU();
|
||||
size_t nCh = masterVU.size();
|
||||
if (nCh == 0)
|
||||
{
|
||||
ImGui::TextDisabled("No audio channels");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// per-channel smoothing & peak-hold
|
||||
static std::vector<float> smooth, peakHold, decay;
|
||||
if (smooth.size() != nCh) {
|
||||
smooth.assign(nCh, 0.0f);
|
||||
peakHold.assign(nCh, 0.0f);
|
||||
decay.assign(nCh, 0.005f);
|
||||
}
|
||||
|
||||
// layout: compute barW clamped to maxBarW, but no centering
|
||||
float availW = ImGui::GetContentRegionAvail().x;
|
||||
const float space = 2.0f;
|
||||
const float maxBar = 40.0f; // maximum bar width
|
||||
float idealBarW = (availW - (nCh - 1)*space) / float(nCh);
|
||||
float barW = std::min(idealBarW, maxBar);
|
||||
float barH = (ImGui::GetContentRegionAvail().y * 0.90) - 25.0f;
|
||||
|
||||
ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
|
||||
// reserve the area for all bars + labels
|
||||
ImGui::Dummy(ImVec2(availW, barH + 20));
|
||||
ImGui::SameLine();
|
||||
ImGui::NewLine();
|
||||
|
||||
for (size_t ch = 0; ch < nCh; ++ch)
|
||||
{
|
||||
float raw = masterVU[ch];
|
||||
|
||||
// smoothing & peak-hold
|
||||
smooth[ch] = 0.1f * raw + 0.9f * smooth[ch];
|
||||
peakHold[ch] = std::max(peakHold[ch], smooth[ch]);
|
||||
peakHold[ch] = std::max(0.0f, peakHold[ch] - decay[ch]);
|
||||
|
||||
// clamp & normalized value
|
||||
float v = std::clamp(smooth[ch], 0.0f, 1.0f);
|
||||
bool clip = (v >= 1.0f);
|
||||
|
||||
// compute dB for display
|
||||
float amp = std::max(v, 1e-5f);
|
||||
float dB = 20.0f * log10f(amp);
|
||||
float norm = std::clamp((dB + 80.0f)/80.0f, 0.0f, 1.0f);
|
||||
|
||||
// choose solid color by dBFS thresholds
|
||||
ImU32 fillCol;
|
||||
if (dB <= -12.0f) {
|
||||
fillCol = IM_COL32(0,255,0,255); // green :contentReference[oaicite:8]{index=8}
|
||||
} else if (dB <= -2.0f) {
|
||||
fillCol = IM_COL32(255,255,0,255); // yellow :contentReference[oaicite:9]{index=9}
|
||||
} else {
|
||||
fillCol = IM_COL32(255,0,0,255); // red (warning) :contentReference[oaicite:10]{index=10}
|
||||
}
|
||||
clip = (dB >= 0.0f); // true clipping at ≥0 dBFS :contentReference[oaicite:11]{index=11}
|
||||
ImU32 bgCol = IM_COL32(50,50,50,200);
|
||||
|
||||
// compute bar rectangle (left-aligned)
|
||||
float x0 = origin.x + ch * (barW + space);
|
||||
float y0 = origin.y;
|
||||
float x1 = x0 + barW;
|
||||
float y1 = y0 + barH;
|
||||
|
||||
// drop-shadow
|
||||
dl->AddRectFilled({x0+2, y0+2}, {x1+2, y1+2}, IM_COL32(0,0,0,80), 3.0f);
|
||||
// background (rounded corners)
|
||||
dl->AddRectFilled({x0, y0}, {x1, y1}, bgCol, 3.0f);
|
||||
// solid level fill
|
||||
float fy = y1 - v*barH;
|
||||
dl->AddRectFilled({x0, fy}, {x1, y1}, fillCol, 3.0f);
|
||||
// peak-hold line
|
||||
float py = y1 - peakHold[ch] * barH;
|
||||
dl->AddLine({x0, py}, {x1, py}, IM_COL32(255,255,255,180), 2.0f);
|
||||
if (clip)
|
||||
dl->AddCircleFilled({x0 + barW*0.5f, y0 - 6}, 4.0f, IM_COL32(255,0,0,255));
|
||||
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "CH%zu", ch+1);
|
||||
float tx = x0 + (barW - ImGui::CalcTextSize(buf).x)*0.5f;
|
||||
dl->AddText({tx, y1 + 2}, IM_COL32(200,200,200,255), buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%.0fdb", dB);
|
||||
tx = x0 + (barW - ImGui::CalcTextSize(buf).x)*0.5f;
|
||||
dl->AddText({tx, y1 + 14}, IM_COL32(255,255,255,200), buf);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
5
src/src/editor/windows/AudioInfo.h
Normal file
5
src/src/editor/windows/AudioInfo.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
// Draw the Audio info window thing
|
||||
void DrawAudioPlayingList();
|
@ -747,6 +747,10 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
|
||||
static float volume = 1.0f;
|
||||
if (ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f))
|
||||
audio->SetVolume(volume);
|
||||
|
||||
|
||||
if (ImGui::Button("Remove AudioPlayerComponent"))
|
||||
selected->RemoveComponent<AudioPlayerComponent>();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
7
src/vendor/miniaudio/miniaudio.c
vendored
Normal file
7
src/vendor/miniaudio/miniaudio.c
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#define MA_ENABLE_MP3
|
||||
#define MA_ENABLE_WAV
|
||||
#define MA_ENABLE_FLAC
|
||||
#define MA_ENABLE_VORBIS
|
||||
#define MA_ENABLE_NODE_GRAPH
|
||||
#include "miniaudio.h"
|
Loading…
Reference in New Issue
Block a user