]> git.localhorst.tv Git - blank.git/commitdiff
some experiments with sound
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sat, 1 Aug 2015 13:00:07 +0000 (15:00 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sat, 1 Aug 2015 13:00:07 +0000 (15:00 +0200)
17 files changed:
Makefile
assets
building
running
src/app/Application.hpp
src/app/Assets.hpp
src/app/Runtime.cpp
src/app/app.cpp
src/app/init.cpp
src/app/init.hpp
src/audio/ALError.hpp [new file with mode: 0644]
src/audio/Audio.hpp [new file with mode: 0644]
src/audio/Sound.hpp [new file with mode: 0644]
src/audio/audio.cpp [new file with mode: 0644]
src/ui/Interface.hpp
src/ui/ui.cpp
src/world/Chunk.hpp

index 2a355cd9f45c0ab187a2e1f7e4dabff72dc75dba..d2e76cadf7d3e3f2dfb426d9790edc5ada08183e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 CXX = g++ --std=c++11
 LDXX = g++
 
-LIBS = sdl2 SDL2_image SDL2_ttf glew
+LIBS = sdl2 SDL2_image SDL2_ttf glew openal freealut
 
 PKGFLAGS := $(shell pkg-config --cflags $(LIBS))
 PKGLIBS := $(shell pkg-config --libs $(LIBS))
diff --git a/assets b/assets
index 7ac546c3310a3f147a889077dffa6919fad94be7..96db33a3047bf3f20f5b6d4464cf4a4ee238146d 160000 (submodule)
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 7ac546c3310a3f147a889077dffa6919fad94be7
+Subproject commit 96db33a3047bf3f20f5b6d4464cf4a4ee238146d
index 3ba784640fd7dea85c27b8c7553fe244763c139f..98e21ecc882734e60eea99bc59999c7b29a6e454 100644 (file)
--- a/building
+++ b/building
@@ -1,11 +1,11 @@
 Dependencies
 ============
 
-       GLEW, GLM, SDL2, SDL2_image, SDL2_ttf
+       GLEW, GLM, SDL2, SDL2_image, SDL2_ttf, OpenAL, freealut
 
        CppUnit for tests
 
-archlinux: pacman -S glew glm sdl2 sdl2_image sdl2_ttf cppunit
+archlinux: pacman -S glew glm sdl2 sdl2_image sdl2_ttf openal freealut cppunit
 
 manual:
        CppUnit http://sourceforge.net/projects/cppunit/
diff --git a/running b/running
index efc10622250668924aa495db9f00d0d3e19e04d8..1684765071195c33501ceeb2cd2d7a696c23fecd 100644 (file)
--- a/running
+++ b/running
@@ -37,6 +37,11 @@ Interface
 --no-hud
        disable HUD drawing (includes the selected block outline)
 
+--no-audio
+       disable audio
+       the audio device and sounds will still be allocated
+       it just stops the interface from queueing buffers
+
 World
 -----
 
@@ -64,4 +69,6 @@ level there. C dumps info about the chunk of the pointed at block.
 
 Press N to toggle player/world collision.
 
+F1 toggles UI rendering.
 F3 toggles a display telling how long on average it takes to compute a frame.
+F4 toggles audio.
index a8e0f2d00f3fdafda8df72d5533e4f86cbfe7c3c..636b82e85899c389a7f69437a001495b638ec428 100644 (file)
@@ -5,6 +5,7 @@
 #include "FrameCounter.hpp"
 #include "init.hpp"
 #include "RandomWalk.hpp"
+#include "../audio/Audio.hpp"
 #include "../graphics/Viewport.hpp"
 #include "../ui/Interface.hpp"
 #include "../world/World.hpp"
@@ -27,6 +28,7 @@ public:
        };
 
        explicit Application(const Config &);
+       ~Application();
 
        Application(const Application &) = delete;
        Application &operator =(const Application &) = delete;
@@ -57,6 +59,7 @@ private:
        Init init;
        Viewport viewport;
        Assets assets;
+       Audio audio;
        FrameCounter counter;
 
        World world;
index d9ab3d443592c0c491079069418caf8f4f5a5c74..4953ddbfcfd75fee41844cdad681b20496d1e0a4 100644 (file)
@@ -7,6 +7,7 @@
 namespace blank {
 
 class Font;
+class Sound;
 
 class Assets {
 
@@ -14,9 +15,11 @@ public:
        explicit Assets(const std::string &base);
 
        Font LoadFont(const std::string &name, int size) const;
+       Sound LoadSound(const std::string &name) const;
 
 private:
        std::string fonts;
+       std::string sounds;
 
 };
 
index 8ddab262e483e34b5f24f01fab08d13b5f9702dd..1dcf722f9e94e06db392822aabad9e6abb6d5782 100644 (file)
@@ -49,6 +49,8 @@ void Runtime::ReadArgs(int argc, const char *const *argv) {
                                                config.interface.mouse_disabled = true;
                                        } else if (strcmp(arg + 2, "no-hud") == 0) {
                                                config.interface.visual_disabled = true;
+                                       } else if (strcmp(arg + 2, "no-audio") == 0) {
+                                               config.interface.audio_disabled = true;
                                        } else {
                                                cerr << "unknown option " << arg << endl;
                                                error = true;
index d13dfc6aafe7c398a633de83d48bef3857b3993f..59070a56311d01c7e129a852b717e9313431aae2 100644 (file)
@@ -2,6 +2,7 @@
 #include "Assets.hpp"
 #include "FrameCounter.hpp"
 
+#include "../audio/Sound.hpp"
 #include "../graphics/Font.hpp"
 #include "../world/BlockType.hpp"
 #include "../world/Entity.hpp"
@@ -30,14 +31,19 @@ Application::Application(const Config &config)
 : init(config.doublebuf, config.multisampling)
 , viewport()
 , assets(get_asset_path())
+, audio()
 , counter()
 , world(config.world)
-, interface(config.interface, assets, counter, world)
+, interface(config.interface, assets, audio, counter, world)
 , test_controller(MakeTestEntity(world))
 , running(false) {
        viewport.VSync(config.vsync);
 }
 
+Application::~Application() {
+       audio.StopAll();
+}
+
 Entity &Application::MakeTestEntity(World &world) {
        Entity &e = world.AddEntity();
        e.Name("test");
@@ -156,6 +162,14 @@ void Application::Update(int dt) {
        interface.Update(dt);
        test_controller.Update(dt);
        world.Update(dt);
+
+       glm::mat4 trans = world.Player().Transform(Chunk::Pos(0, 0, 0));
+       glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));
+       glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
+       audio.Position(world.Player().Position());
+       audio.Velocity(world.Player().Velocity());
+       audio.Orientation(dir, up);
+
        counter.ExitUpdate();
 }
 
@@ -174,7 +188,8 @@ void Application::Render() {
 
 
 Assets::Assets(const string &base)
-: fonts(base + "fonts/") {
+: fonts(base + "fonts/")
+, sounds(base + "sounds/") {
 
 }
 
@@ -183,6 +198,11 @@ Font Assets::LoadFont(const string &name, int size) const {
        return Font(full.c_str(), size);
 }
 
+Sound Assets::LoadSound(const string &name) const {
+       string full = sounds + name + ".wav";
+       return Sound(full.c_str());
+}
+
 
 void FrameCounter::EnterFrame() noexcept {
        last_enter = SDL_GetTicks();
index 1cc0c2485b50db7e79a5fdd5baf242ef4201a72d..18816a424bdb3a972341311d72a9cda19fa19ac6 100644 (file)
@@ -1,6 +1,7 @@
 #include "init.hpp"
 
 #include <algorithm>
+#include <alut.h>
 #include <SDL.h>
 #include <SDL_image.h>
 #include <SDL_ttf.h>
@@ -19,10 +20,30 @@ std::string sdl_error_append(std::string msg) {
        return msg;
 }
 
+std::string alut_error_append(ALenum num, std::string msg) {
+       const char *error = alutGetErrorString(num);
+       if (*error != '\0') {
+               msg += ": ";
+               msg += error;
+       }
+       return msg;
+}
+
 }
 
 namespace blank {
 
+AlutError::AlutError(ALenum num)
+: std::runtime_error(alutGetErrorString(num)) {
+
+}
+
+AlutError::AlutError(ALenum num, const std::string &msg)
+: std::runtime_error(alut_error_append(num, msg)) {
+
+}
+
+
 SDLError::SDLError()
 : std::runtime_error(SDL_GetError()) {
 
@@ -67,6 +88,19 @@ InitTTF::~InitTTF() {
 }
 
 
+InitAL::InitAL() {
+       if (!alutInit(nullptr, nullptr)) {
+               throw AlutError(alutGetError(), "alutInit");
+       }
+}
+
+InitAL::~InitAL() {
+       if (!alutExit()) {
+               throw AlutError(alutGetError(), "alutExit");
+       }
+}
+
+
 InitGL::InitGL(bool double_buffer, int sample_size) {
        if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) != 0) {
                throw SDLError("SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)");
index 122210d1e96bc426a33de8b8a6fb938eda02976e..13bffa1f30e8886087ac441319f0f9af766f8aa3 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef BLANK_APP_INIT_HPP_
 #define BLANK_APP_INIT_HPP_
 
+#include <al.h>
 #include <SDL.h>
 #include <stdexcept>
 #include <string>
@@ -8,6 +9,15 @@
 
 namespace blank {
 
+class AlutError
+: public std::runtime_error {
+
+public:
+       explicit AlutError(ALenum);
+       AlutError(ALenum, const std::string &);
+
+};
+
 class SDLError
 : public std::runtime_error {
 
@@ -54,6 +64,18 @@ public:
 };
 
 
+class InitAL {
+
+public:
+       InitAL();
+       ~InitAL();
+
+       InitAL(const InitAL &) = delete;
+       InitAL &operator =(const InitAL &) = delete;
+
+};
+
+
 class InitGL {
 
 public:
@@ -123,6 +145,7 @@ struct Init {
        InitSDL init_sdl;
        InitIMG init_img;
        InitTTF init_ttf;
+       InitAL init_al;
        InitGL init_gl;
        Window window;
        GLContext ctx;
diff --git a/src/audio/ALError.hpp b/src/audio/ALError.hpp
new file mode 100644 (file)
index 0000000..973bcef
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef BLANK_AUDIO_ALERROR_HPP_
+#define BLANK_AUDIO_ALERROR_HPP_
+
+#include <al.h>
+#include <stdexcept>
+#include <string>
+
+
+namespace blank {
+
+class ALError
+: public std::runtime_error {
+
+public:
+       explicit ALError(ALenum);
+       ALError(ALenum, const std::string &);
+
+};
+
+}
+
+#endif
diff --git a/src/audio/Audio.hpp b/src/audio/Audio.hpp
new file mode 100644 (file)
index 0000000..fe5364d
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef BLANK_AUDIO_AUDIO_HPP_
+#define BLANK_AUDIO_AUDIO_HPP_
+
+#include <al.h>
+#include <glm/glm.hpp>
+
+
+namespace blank {
+
+class Sound;
+
+class Audio {
+
+public:
+       Audio();
+       ~Audio();
+
+       Audio(const Audio &) = delete;
+       Audio &operator =(const Audio &) = delete;
+
+public:
+       void Position(const glm::vec3 &) noexcept;
+       void Velocity(const glm::vec3 &) noexcept;
+       void Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept;
+
+       void Play(
+               const Sound &,
+               const glm::vec3 &pos = glm::vec3(0.0f),
+               const glm::vec3 &vel = glm::vec3(0.0f),
+               const glm::vec3 &dir = glm::vec3(0.0f)
+       ) noexcept;
+
+       void StopAll() noexcept;
+
+private:
+       static constexpr std::size_t NUM_SRC = 1;
+       ALuint source[NUM_SRC];
+
+};
+
+}
+
+#endif
diff --git a/src/audio/Sound.hpp b/src/audio/Sound.hpp
new file mode 100644 (file)
index 0000000..abbb27b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef BLANK_AUDIO_SOUND_HPP_
+#define BLANK_AUDIO_SOUND_HPP_
+
+#include <al.h>
+
+
+namespace blank {
+
+class Sound {
+
+public:
+       Sound();
+       explicit Sound(const char *);
+       ~Sound();
+
+       Sound(Sound &&);
+       Sound &operator =(Sound &&);
+
+       Sound(const Sound &) = delete;
+       Sound &operator =(const Sound &) = delete;
+
+public:
+       void Bind(ALuint src) const;
+
+private:
+       ALuint handle;
+
+};
+
+}
+
+#endif
diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp
new file mode 100644 (file)
index 0000000..eed5dac
--- /dev/null
@@ -0,0 +1,154 @@
+#include "ALError.hpp"
+#include "Audio.hpp"
+#include "Sound.hpp"
+
+#include <algorithm>
+#include <alut.h>
+#include <iostream>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/io.hpp>
+
+
+namespace {
+
+const char *al_error_string(ALenum num) {
+       switch (num) {
+               case AL_NO_ERROR:
+                       return "no error";
+               case AL_INVALID_NAME:
+                       return "invalid name";
+               case AL_INVALID_ENUM:
+                       return "invalid enum";
+               case AL_INVALID_VALUE:
+                       return "invalid value";
+               case AL_INVALID_OPERATION:
+                       return "invalid operation";
+               case AL_OUT_OF_MEMORY:
+                       return "out of memory";
+       }
+       return "unknown AL error";
+}
+
+std::string al_error_append(ALenum num, std::string msg) {
+       return msg + ": " + al_error_string(num);
+}
+
+}
+
+namespace blank {
+
+ALError::ALError(ALenum num)
+: std::runtime_error(al_error_string(num)) {
+
+}
+
+ALError::ALError(ALenum num, const std::string &msg)
+: std::runtime_error(al_error_append(num, msg)) {
+
+}
+
+
+Audio::Audio() {
+       alGenSources(NUM_SRC, source);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               throw ALError(err, "alGenSources");
+       }
+       for (std::size_t i = 0; i < NUM_SRC; ++i) {
+               alSourcef(source[i], AL_REFERENCE_DISTANCE, 2.0f);
+               alSourcef(source[i], AL_ROLLOFF_FACTOR, 1.0f);
+       }
+}
+
+Audio::~Audio() {
+       alDeleteSources(NUM_SRC, source);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               std::cerr << "warning: alDeleteSources failed with " << al_error_string(err) << std::endl;
+               //throw ALError(err, "alDeleteSources");
+       }
+}
+
+void Audio::Position(const glm::vec3 &pos) noexcept {
+       alListenerfv(AL_POSITION, glm::value_ptr(pos));
+       //std::cout << "listener at " << pos << std::endl;
+}
+
+void Audio::Velocity(const glm::vec3 &vel) noexcept {
+       alListenerfv(AL_VELOCITY, glm::value_ptr(vel));
+}
+
+void Audio::Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept {
+       ALfloat orient[6] = {
+               dir.x, dir.y, dir.z,
+               up.x, up.y, up.z,
+       };
+       alListenerfv(AL_ORIENTATION, orient);
+}
+
+void Audio::Play(
+       const Sound &sound,
+       const glm::vec3 &pos,
+       const glm::vec3 &vel,
+       const glm::vec3 &dir
+) noexcept {
+       // TODO: find next free source
+       ALuint src = source[0];
+
+       sound.Bind(src);
+       alSourcefv(src, AL_POSITION, glm::value_ptr(pos));
+       alSourcefv(src, AL_VELOCITY, glm::value_ptr(vel));
+       alSourcefv(src, AL_DIRECTION, glm::value_ptr(dir));
+       alSourcePlay(src);
+}
+
+void Audio::StopAll() noexcept {
+       alSourceStopv(NUM_SRC, source);
+       for (std::size_t i = 0; i < NUM_SRC; ++i) {
+               alSourcei(source[i], AL_BUFFER, AL_NONE);
+       }
+}
+
+
+Sound::Sound()
+: handle(AL_NONE) {
+       alGenBuffers(1, &handle);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               throw ALError(err, "alGenBuffers");
+       }
+}
+
+Sound::Sound(const char *file)
+: handle(alutCreateBufferFromFile(file)) {
+       if (handle == AL_NONE) {
+               throw ALError(alGetError(), "alutCreateBufferFromFile");
+       }
+}
+
+Sound::~Sound() {
+       if (handle != AL_NONE) {
+               alDeleteBuffers(1, &handle);
+               ALenum err = alGetError();
+               if (err != AL_NO_ERROR) {
+                       std::cerr << "warning: alDeleteBuffers failed with " << al_error_string(err) << std::endl;
+                       //throw ALError(err, "alDeleteBuffers");
+               }
+       }
+}
+
+Sound::Sound(Sound &&other)
+: handle(other.handle) {
+       other.handle = AL_NONE;
+}
+
+Sound &Sound::operator =(Sound &&other) {
+       std::swap(handle, other.handle);
+       return *this;
+}
+
+void Sound::Bind(ALuint src) const {
+       alSourcei(src, AL_BUFFER, handle);
+}
+
+}
index 00b76e66b0c2232ea48cfc0eec1f053e03c3aaac..eaed0fc0b15b5122752bedad02397068a0fcacc3 100644 (file)
@@ -4,6 +4,7 @@
 #include "HUD.hpp"
 #include "../app/FPSController.hpp"
 #include "../app/IntervalTimer.hpp"
+#include "../audio/Sound.hpp"
 #include "../graphics/FixedText.hpp"
 #include "../graphics/Font.hpp"
 #include "../graphics/MessageBox.hpp"
@@ -18,6 +19,7 @@
 namespace blank {
 
 class Assets;
+class Audio;
 class Chunk;
 class FrameCounter;
 class Viewport;
@@ -33,10 +35,11 @@ public:
 
                bool keyboard_disabled = false;
                bool mouse_disabled = false;
+               bool audio_disabled = false;
                bool visual_disabled = false;
        };
 
-       Interface(const Config &, const Assets &, const FrameCounter &, World &);
+       Interface(const Config &, const Assets &, Audio &, const FrameCounter &, World &);
 
        void HandlePress(const SDL_KeyboardEvent &);
        void HandleRelease(const SDL_KeyboardEvent &);
@@ -63,6 +66,9 @@ public:
        void SelectNext();
        void SelectPrevious();
 
+       void ToggleAudio();
+       void ToggleVisual();
+
        void ToggleCounter();
        void UpdateCounter();
 
@@ -79,6 +85,7 @@ private:
        void CheckAim();
 
 private:
+       Audio &audio;
        const FrameCounter &counter;
        World &world;
        FPSController ctrl;
@@ -105,6 +112,9 @@ private:
        Block remove;
        Block selection;
 
+       Sound place_sound;
+       Sound remove_sound;
+
        glm::tvec3<int> fwd, rev;
 
 };
index 43a5f5d1ca68ef5b44d9ad3766d99e1154dd5670..8a17be2b873b80ae3cddd9b855f5e69815757e62 100644 (file)
@@ -4,6 +4,7 @@
 #include "../app/Assets.hpp"
 #include "../app/FrameCounter.hpp"
 #include "../app/init.hpp"
+#include "../audio/Audio.hpp"
 #include "../graphics/Font.hpp"
 #include "../graphics/Viewport.hpp"
 #include "../model/shapes.hpp"
@@ -91,9 +92,11 @@ void HUD::Render(Viewport &viewport) noexcept {
 Interface::Interface(
        const Config &config,
        const Assets &assets,
+       Audio &audio,
        const FrameCounter &counter,
        World &world)
-: counter(counter)
+: audio(audio)
+, counter(counter)
 , world(world)
 , ctrl(world.Player())
 , font(assets.LoadFont("DejaVuSans", 16))
@@ -112,6 +115,8 @@ Interface::Interface(
 , remove_timer(256)
 , remove(0)
 , selection(1)
+, place_sound(assets.LoadSound("thump"))
+, remove_sound(assets.LoadSound("plop"))
 , fwd(0)
 , rev(0) {
        counter_text.Hide();
@@ -172,9 +177,15 @@ void Interface::HandlePress(const SDL_KeyboardEvent &event) {
                        PrintSelectionInfo();
                        break;
 
+               case SDLK_F1:
+                       ToggleVisual();
+                       break;
                case SDLK_F3:
                        ToggleCounter();
                        break;
+               case SDLK_F4:
+                       ToggleAudio();
+                       break;
        }
 }
 
@@ -308,6 +319,24 @@ void Interface::Print(const Block &block) {
        PostMessage(s.str());
 }
 
+void Interface::ToggleAudio() {
+       config.audio_disabled = !config.audio_disabled;
+       if (config.audio_disabled) {
+               PostMessage("audio off");
+       } else {
+               PostMessage("audio on");
+       }
+}
+
+void Interface::ToggleVisual() {
+       config.visual_disabled = !config.visual_disabled;
+       if (config.visual_disabled) {
+               PostMessage("visual off");
+       } else {
+               PostMessage("visual on");
+       }
+}
+
 void Interface::ToggleCounter() {
        counter_text.Toggle();
        if (counter_text.Visible()) {
@@ -371,12 +400,26 @@ void Interface::PlaceBlock() {
        }
        mod_chunk->SetBlock(next_pos, selection);
        mod_chunk->Invalidate();
+
+       if (config.audio_disabled) return;
+       const Entity &player = ctrl.Controlled();
+       audio.Play(
+               place_sound,
+               mod_chunk->ToSceneCoords(player.ChunkCoords(), next_pos)
+       );
 }
 
 void Interface::RemoveBlock() noexcept {
        if (!aim_chunk) return;
        aim_chunk->SetBlock(aim_block, remove);
        aim_chunk->Invalidate();
+
+       if (config.audio_disabled) return;
+       const Entity &player = ctrl.Controlled();
+       audio.Play(
+               remove_sound,
+               aim_chunk->ToSceneCoords(player.ChunkCoords(), Chunk::ToCoords(aim_block))
+       );
 }
 
 
index a75d8e202ddb3e5544fb0f7cc25e3b44c2a650f5..535f7d76806f5a404e96282985f6e29ff8b96a98 100644 (file)
@@ -73,6 +73,10 @@ public:
        }
        glm::mat4 ToTransform(const Pos &pos, int idx) const noexcept;
 
+       Block::Pos ToSceneCoords(const Pos &base, const Block::Pos &pos) const noexcept {
+               return Block::Pos((position - base) * Extent()) + pos;
+       }
+
        static bool IsBorder(const Pos &pos) noexcept {
                return
                        pos.x == 0 ||