From 81cf0e07197c6ac60ac6fa20a60fee28ee41f8e4 Mon Sep 17 00:00:00 2001 From: darkrose Date: Mon, 19 Jun 2017 03:56:34 +1000 Subject: [PATCH] sound pt1 --- src/CMakeLists.txt | 7 +- src/array.c | 1 + src/ban.c | 1 + src/client.cpp | 47 +-- src/client.h | 5 +- src/common.h | 2 +- src/config.c | 12 +- src/config_default.c | 7 +- src/content_cao.cpp | 2 +- src/content_list.c | 2 + src/file.c | 2 + src/game.cpp | 29 +- src/game.h | 3 +- src/guiMainMenu.cpp | 9 +- src/guiMainMenu.h | 6 +- src/guiSettingsMenu.cpp | 104 ++++++- src/guiSettingsMenu.h | 12 +- src/intl.c | 2 + src/intl.h | 2 +- src/main.cpp | 32 +- src/map.cpp | 2 + src/mapblock.cpp | 8 +- src/mapblock_mesh.cpp | 5 +- src/player.cpp | 17 +- src/server.cpp | 6 - src/server.h | 2 - src/sound.c | 647 ++++++++++++++++++++++++++++++++++++++++ src/sound.h | 145 ++++----- src/sound_ogg.c | 123 ++++++++ src/sound_wav.c | 105 +++++++ src/thread.c | 1 + 31 files changed, 1131 insertions(+), 217 deletions(-) create mode 100644 src/sound.c create mode 100644 src/sound_ogg.c create mode 100644 src/sound_wav.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2dbf25..f3c33b3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,7 +46,7 @@ if(SOUND_PROBLEM) "To continue, either fill in the required paths or disable sound. (-DENABLE_AUDIO=0)") endif() if(USE_AUDIO) - set(audio_SRCS sound.cpp sound_openal.cpp) + set(audio_SRCS sound.c sound_ogg.c sound_wav.c) set(AUDIO_INCLUDE_DIRS ${OPENAL_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR} @@ -56,8 +56,6 @@ if(USE_AUDIO) ${OPENAL_LIBRARY} ${VORBIS_LIBRARIES} ) -else() - set(audio_SRCS sound.cpp) endif() option(ENABLE_FREETYPE "Enable freetype2 (truetype fonts and basic unicode support)" ON) @@ -279,7 +277,6 @@ set(voxelands_SRCS # Server sources set(voxelandsserver_SRCS ${common_SRCS} - ${audio_SRCS} servermain.cpp ) @@ -415,7 +412,7 @@ else() set(CMAKE_CXX_FLAGS_RELEASE "${OPT_FLAGS} ${SAFETY_FLAGS} -Wall -DNDEBUG -pipe -fpermissive -Wno-write-strings") - set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) + set(CMAKE_C_FLAGS_RELEASE "${OPT_FLAGS} ${SAFETY_FLAGS} -Wall -DNDEBUG -pipe -ansi -pedantic") set(CMAKE_CXX_FLAGS_DEBUG "${SAFETY_FLAGS} -Wall -O0 -g3 -ggdb -fpermissive -Wno-write-strings") set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) diff --git a/src/array.c b/src/array.c index dd4c025..89d45db 100644 --- a/src/array.c +++ b/src/array.c @@ -17,6 +17,7 @@ * along with this program. If not, see ************************************************************************/ +#include "common.h" #include "array.h" #include diff --git a/src/ban.c b/src/ban.c index b4e2044..ab74804 100644 --- a/src/ban.c +++ b/src/ban.c @@ -17,6 +17,7 @@ * along with this program. If not, see ************************************************************************/ +#include "common.h" #include "ban.h" #include "file.h" diff --git a/src/client.cpp b/src/client.cpp index 66c0119..c9ed449 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -202,8 +202,7 @@ void * MeshUpdateThread::Thread() Client::Client( IrrlichtDevice *device, std::string password, - MapDrawControl &control, - ISoundManager *sound): + MapDrawControl &control): m_mesh_update_thread(), m_env( this, @@ -216,7 +215,6 @@ Client::Client( m_server_suffocation(false), m_server_hunger(false), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), - m_sound(sound), m_device(device), m_server_ser_ver(SER_FMT_VER_INVALID), m_inventory_updated(false), @@ -1624,7 +1622,8 @@ void Client::useItem() // Send as reliable Send(0, data, true); - if (g_sound) { +#if USE_AUDIO == 1 + { InventoryItem *item = (InventoryItem*)m_env.getLocalPlayer()->getWieldItem(); if (!item) return; @@ -1633,8 +1632,9 @@ void Client::useItem() if ((w&CONTENT_CRAFTITEM_MASK) == CONTENT_CRAFTITEM_MASK) snd = content_craftitem_features(w)->sound_use; if (snd != "") - g_sound->playSound(snd,false); + sound_play_effect(snd.c_str(),1.0,NULL); } +#endif } void Client::clickActiveObject(u8 button, u16 id, u16 item_i) @@ -2284,27 +2284,14 @@ float Client::getRTT(void) } } -ISoundManager* Client::getSoundManager() -{ - if (m_sound == NULL) - return &dummySoundManager; - return m_sound; -} - // foot: 0 = left, 1 = right void Client::playStepSound(int foot) { - if (!g_sound) - return; - - sound_playStep(&m_env.getMap(),m_env.getLocalPlayer()->getPosition(),foot); + //sound_playStep(&m_env.getMap(),m_env.getLocalPlayer()->getPosition(),foot); } void Client::playDigSound(content_t c) { - if (!g_sound) - return; - if (c == CONTENT_IGNORE) { c = getPointedContent(); if ((c&CONTENT_MOB_MASK) != 0) @@ -2313,41 +2300,37 @@ void Client::playDigSound(content_t c) if (c == CONTENT_IGNORE) c = CONTENT_AIR; - sound_playDig(c,m_env.getLocalPlayer()->getPosition()); + //sound_playDig(c,m_env.getLocalPlayer()->getPosition()); } void Client::playPlaceSound(content_t c) { - if (!m_sound) - return; - if (c == CONTENT_IGNORE) c = getPointedContent(); ContentFeatures *f = &content_features(c); if (f->sound_place != "") { - m_sound->playSound(f->sound_place,false); + sound_play_effect((char*)f->sound_place.c_str(),1.0,NULL); return; } switch (f->type) { case CMT_LIQUID: - m_sound->playSound("liquid-place",false); + sound_play_effect("liquid-place",1.0,NULL); break; default: - m_sound->playSound("place",false); + sound_play_effect("place",1.0,NULL); } } void Client::playSound(std::string &name, bool loop) { - if (!m_sound) - return; - m_sound->playSound(name,loop); + /* TODO: looping */ + sound_play_effect((char*)name.c_str(),1.0,NULL); } void Client::playSoundAt(std::string &name, v3f pos, bool loop) { - if (!m_sound) - return; - m_sound->playSoundAt(name,loop,pos); + v3_t p = {pos.X,pos.Y,pos.Z}; + /* TODO: looping */ + sound_play_effect((char*)name.c_str(),1.0,&p); } diff --git a/src/client.h b/src/client.h index 23224a2..e12c5a6 100644 --- a/src/client.h +++ b/src/client.h @@ -170,8 +170,7 @@ public: Client( IrrlichtDevice *device, std::string password, - MapDrawControl &control, - ISoundManager *sound + MapDrawControl &control ); ~Client(); @@ -323,7 +322,6 @@ public: } float getRTT(void); - virtual ISoundManager* getSoundManager(); void playStepSound(int foot); void playDigSound(content_t c); @@ -385,7 +383,6 @@ private: bool m_server_hunger; con::Connection m_con; - ISoundManager *m_sound; IrrlichtDevice *m_device; diff --git a/src/common.h b/src/common.h index 29963d4..be444e4 100644 --- a/src/common.h +++ b/src/common.h @@ -95,7 +95,7 @@ void config_set_float(char* name, float value); void config_set_default(char* name, char* value, int (*setter)(char* v)); void config_set_default_int(char* name, int value, int (*setter)(char* v)); void config_set_default_float(char* name, float value, int (*setter)(char* v)); -void config_load(char* file); +void config_load(char* type, char* file); int config_load_command(command_context_t *ctx, array_t *args); int config_ignore_command(command_context_t *ctx, array_t *args); void config_init(int argc, char** argv); diff --git a/src/config.c b/src/config.c index a4a7bec..542f201 100644 --- a/src/config.c +++ b/src/config.c @@ -241,14 +241,18 @@ void config_set_default_float(char* name, float value, int (*setter)(char* v)) } /* load a config file */ -void config_load(char* file) +void config_load(char* type, char* file) { char buff[2048]; int s; char* l; + file_t *f; command_context_t ctx; - file_t *f = file_load("config",file); + if (!type) + type = "config"; + + f = file_load(type,file); if (!f) return; @@ -284,7 +288,7 @@ int config_load_command(command_context_t *ctx, array_t *args) f = array_get_string(args,0); nvp_set(&config.files,f,"true",NULL); - config_load(f); + config_load("config",f); return 0; } @@ -332,7 +336,7 @@ void config_init(int argc, char** argv) n = config.files; while (n) { if (n->value && !strcmp(n->value,"true")) - config_load(n->name); + config_load("config",n->name); n = n->next; } diff --git a/src/config_default.c b/src/config_default.c index cf6bec2..f5148aa 100644 --- a/src/config_default.c +++ b/src/config_default.c @@ -19,6 +19,9 @@ #include "common.h" #include "path.h" +#ifndef SERVER +#include "sound.h" +#endif #include @@ -53,7 +56,9 @@ void config_default_init() config_set_default("client.video.driver","opengl",NULL); config_set_default("client.video.hpfpu","true",NULL); - config_set_default("client.sound.volume","50",NULL); + config_set_default("client.sound.volume","50",sound_master_setter); + config_set_default("client.sound.volume.effects","50",sound_effects_setter); + config_set_default("client.sound.volume.music","50",sound_music_setter); config_set_default("client.graphics.mesh.lod","3",NULL); config_set_default("client.graphics.texture.animations","true",NULL); diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 42f2515..8b638f7 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -272,7 +272,7 @@ void MobCAO::step(float dtime, ClientEnvironment *env) /* roughly sort of when a step sound should probably be heard, maybe */ if (m_last_step > 0.5) { m_last_step -= 0.5; - sound_playStep(&env->getMap(),m_position,m_next_foot, 0.3); + //sound_playStep(&env->getMap(),m_position,m_next_foot, 0.3); m_next_foot = !m_next_foot; } } diff --git a/src/content_list.c b/src/content_list.c index ce9cc83..567366b 100644 --- a/src/content_list.c +++ b/src/content_list.c @@ -17,6 +17,8 @@ * along with this program. If not, see ************************************************************************/ +#include "common.h" + #include #include diff --git a/src/file.c b/src/file.c index 36cbb84..1d313df 100644 --- a/src/file.c +++ b/src/file.c @@ -17,6 +17,8 @@ * along with this program. If not, see ************************************************************************/ +#include "common.h" + #include "file.h" #include "path.h" diff --git a/src/game.cpp b/src/game.cpp index 6fc194d..a980ce6 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -642,8 +642,7 @@ void the_game( IrrlichtDevice *device, gui::IGUIFont* font, std::string password, - std::wstring &error_message, - ISoundManager *sound + std::wstring &error_message ) { video::IVideoDriver* driver = device->getVideoDriver(); @@ -689,7 +688,7 @@ void the_game( drawLoadingScreen(device,narrow_to_wide(gettext("Creating client..."))); infostream<<"Creating client"<maintain(dtime); - } -#endif - { // Read client events while (1) { @@ -1499,7 +1492,8 @@ void the_game( if (event.player_damage.amount >= 2) { damage_flash_timer += 0.05 * event.player_damage.amount; } - if (g_sound) { +#if USE_AUDIO == 1 + { char* v; std::string ch = std::string(PLAYER_DEFAULT_CHARDEF); v = config_get("client.character"); @@ -1509,8 +1503,9 @@ void the_game( std::string gender = f.next(":"); std::string snd("player-hurt-"); snd += gender; - g_sound->playSound(snd,false); + sound_play_effect((char*)snd.c_str(),1.0,NULL); } +#endif }else if (event.type == CE_PLAYER_FORCE_MOVE) { camera_yaw = event.player_force_move.yaw; camera_pitch = event.player_force_move.pitch; @@ -1541,16 +1536,18 @@ void the_game( v3f player_position = player->getPosition(); v3f camera_position = camera.getPosition(); v3f camera_direction = camera.getDirection(); + v3f camera_up = camera.getCameraNode()->getUpVector(); f32 camera_fov = camera.getFovMax(); v3s16 camera_offset = camera.getOffset(); +#if USE_AUDIO == 1 { - ISoundManager *snd = client.getSoundManager(); - if (snd) - snd->updateListener(camera_position,v3f(0,0,0),camera_direction,camera.getCameraNode()->getUpVector()); + v3_t pos = {camera_position.X,camera_position.Y,camera_position.Z}; + v3_t at = {camera_direction.X,camera_direction.Y,camera_direction.Z}; + v3_t up = {camera_up.X,camera_up.Y,camera_up.Z}; + sound_step(dtime,&pos,&at,&up); } - - //bool camera_offset_changed = (camera_offset != old_camera_offset); +#endif if (!disable_camera_update) { client.updateCamera(camera_position, camera_direction, camera_fov, camera_offset); diff --git a/src/game.h b/src/game.h index 70e38d8..a82b22d 100644 --- a/src/game.h +++ b/src/game.h @@ -139,8 +139,7 @@ void the_game( IrrlichtDevice *device, gui::IGUIFont* font, std::string password, - std::wstring &error_message, - ISoundManager *sound + std::wstring &error_message ); #endif diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index 451e0fa..0310062 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -52,15 +52,11 @@ GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, MainMenuData *data, - IGameCallback *gamecallback, - ISoundManager *sound + IGameCallback *gamecallback ): GUIModalMenu(env, parent, id, menumgr), m_data(data), m_accepted(false), -#if USE_SOUND == 1 - m_sound(sound), -#endif m_gamecallback(gamecallback) { assert(m_data); @@ -223,7 +219,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) txt += "\ndarkrose, sdzen, Menche, tiemay, JHeaton, MavJS, mcnalu.\n\n"; txt += gettext("Music and Sound Effects Composers"); - txt += "\ndarkrose, Jordach, AudioRichter, OwlStorm, DjDust, Taira Komori.\n\n"; + txt += "\ndarkrose, Jordach, AudioRichter, Tom Peter, OwlStorm, DjDust, Taira Komori.\n\n"; txt += gettext("Other Contributers, and Special Thanks"); txt += "\nnadnadnad, Honeypaw, tiemay, stormchaser3000, MichaelEh?, NCC74656.\n\n"; @@ -362,6 +358,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event) acceptInput(); m_accepted = false; m_data->selected_tab = TAB_CREDITS; + config_set("client.ui.mainmenu.tab","credits"); regenerateGui(m_screensize); return true; case GUI_ID_TAB_QUIT: diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index e2b6d01..943a406 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -118,8 +118,7 @@ public: gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, MainMenuData *data, - IGameCallback *gamecallback, - ISoundManager *sound); + IGameCallback *gamecallback); ~GUIMainMenu(); void removeChildren(); @@ -148,9 +147,6 @@ private: MainMenuData *m_data; bool m_accepted; IGameCallback *m_gamecallback; -#if USE_SOUND == 1 - ISoundManager *m_sound; -#endif gui::IGUIEnvironment* env; gui::IGUIElement* parent; diff --git a/src/guiSettingsMenu.cpp b/src/guiSettingsMenu.cpp index 11c708b..14a7e48 100644 --- a/src/guiSettingsMenu.cpp +++ b/src/guiSettingsMenu.cpp @@ -66,7 +66,9 @@ GUISettingsMenu::GUISettingsMenu( m_data.trilinear_filter = config_get_bool("client.video.trilinear"); m_data.hotbar = config_get_bool("client.ui.hud.old"); m_data.wield_index = config_get_bool("client.ui.hud.wieldindex"); - m_data.volume = config_get_float("client.sound.volume"); + m_data.volume_master = config_get_float("client.sound.volume"); + m_data.volume_effects = config_get_float("client.sound.volume.effects"); + m_data.volume_music = config_get_float("client.sound.volume.music"); m_data.texture_animation = config_get_bool("client.graphics.texture.animations"); keynames[VLKC_FORWARD] = narrow_to_wide(gettext("Forward")); @@ -135,7 +137,6 @@ void GUISettingsMenu::save() config_set_int("client.video.trilinear",m_data.trilinear_filter); config_set_int("client.ui.hud.old",m_data.hotbar); config_set_int("client.ui.hud.wieldindex",m_data.wield_index); - config_set_float("client.sound.volume",m_data.volume); config_set_int("client.graphics.texture.animations",m_data.texture_animation); Environment->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, m_data.mip_map); } @@ -154,7 +155,9 @@ void GUISettingsMenu::regenerateGui(v2u32 screensize) bool hotbar; bool wield_index; bool texture_animation; - f32 volume; + f32 volume_master; + f32 volume_effects; + f32 volume_music; m_screensize = screensize; @@ -285,11 +288,25 @@ void GUISettingsMenu::regenerateGui(v2u32 screensize) wield_index = m_data.wield_index; } { - gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_SB); + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_MASTER_SB); if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) - volume = (float)((gui::IGUIScrollBar*)e)->getPos(); + volume_master = (float)((gui::IGUIScrollBar*)e)->getPos(); else - volume = m_data.volume; + volume_master = m_data.volume_master; + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_EFFECTS_SB); + if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) + volume_effects = (float)((gui::IGUIScrollBar*)e)->getPos(); + else + volume_effects = m_data.volume_effects; + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_MUSIC_SB); + if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) + volume_music = (float)((gui::IGUIScrollBar*)e)->getPos(); + else + volume_music = m_data.volume_music; } /* Remove stuff @@ -534,15 +551,41 @@ void GUISettingsMenu::regenerateGui(v2u32 screensize) { core::rect rect(0, 0, 200, 15); rect += topleft_content + v2s32(80, 60); - Environment->addStaticText(narrow_to_wide(gettext("Volume:")).c_str(), rect, false, false, this, -1); + Environment->addStaticText(narrow_to_wide(gettext("Master Volume:")).c_str(), rect, false, false, this, -1); } { core::rect rect(0, 0, 200, 15); rect += topleft_content + v2s32(290, 60); - gui::IGUIScrollBar *sb = Environment->addScrollBar(true, rect, this, GUI_ID_VOLUME_SB); + gui::IGUIScrollBar *sb = Environment->addScrollBar(true, rect, this, GUI_ID_VOLUME_MASTER_SB); sb->setMin(0); sb->setMax(100); - sb->setPos(volume); + sb->setPos(volume_master); + } + { + core::rect rect(0, 0, 200, 15); + rect += topleft_content + v2s32(80, 90); + Environment->addStaticText(narrow_to_wide(gettext("Effects Volume:")).c_str(), rect, false, false, this, -1); + } + { + core::rect rect(0, 0, 200, 15); + rect += topleft_content + v2s32(290, 90); + gui::IGUIScrollBar *sb = Environment->addScrollBar(true, rect, this, GUI_ID_VOLUME_EFFECTS_SB); + sb->setMin(0); + sb->setMax(100); + sb->setPos(volume_effects); + } + { + core::rect rect(0, 0, 200, 15); + rect += topleft_content + v2s32(80, 120); + Environment->addStaticText(narrow_to_wide(gettext("Music Volume:")).c_str(), rect, false, false, this, -1); + } + { + core::rect rect(0, 0, 200, 15); + rect += topleft_content + v2s32(290, 120); + gui::IGUIScrollBar *sb = Environment->addScrollBar(true, rect, this, GUI_ID_VOLUME_MUSIC_SB); + sb->setMin(0); + sb->setMax(100); + sb->setPos(volume_music); } } } @@ -693,9 +736,19 @@ bool GUISettingsMenu::acceptInput() m_data.wield_index = ((gui::IGUICheckBox*)e)->isChecked(); } { - gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_SB); + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_MASTER_SB); if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) - m_data.volume = (float)((gui::IGUIScrollBar*)e)->getPos(); + m_data.volume_master = (float)((gui::IGUIScrollBar*)e)->getPos(); + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_EFFECTS_SB); + if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) + m_data.volume_effects = (float)((gui::IGUIScrollBar*)e)->getPos(); + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_VOLUME_MUSIC_SB); + if(e != NULL && e->getType() == gui::EGUIET_SCROLL_BAR) + m_data.volume_music = (float)((gui::IGUIScrollBar*)e)->getPos(); } return true; } @@ -794,15 +847,34 @@ bool GUISettingsMenu::OnEvent(const SEvent& event) } if (event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED) { switch (event.GUIEvent.Caller->getID()) { - case GUI_ID_VOLUME_SB: - gui::IGUIElement *vsb = getElementFromId(GUI_ID_VOLUME_SB); + case GUI_ID_VOLUME_MASTER_SB: + { + gui::IGUIElement *vsb = getElementFromId(GUI_ID_VOLUME_MASTER_SB); if(vsb != NULL && vsb->getType() == gui::EGUIET_SCROLL_BAR) { - m_data.volume = (float)((gui::IGUIScrollBar*)vsb)->getPos(); - if (g_sound) - g_sound->setListenerGain(m_data.volume/100.0); + m_data.volume_master = (float)((gui::IGUIScrollBar*)vsb)->getPos(); + config_set_int("client.sound.volume",m_data.volume_master); } return true; } + case GUI_ID_VOLUME_EFFECTS_SB: + { + gui::IGUIElement *vsb = getElementFromId(GUI_ID_VOLUME_EFFECTS_SB); + if(vsb != NULL && vsb->getType() == gui::EGUIET_SCROLL_BAR) { + m_data.volume_effects = (float)((gui::IGUIScrollBar*)vsb)->getPos(); + config_set_int("client.sound.volume.effects",m_data.volume_effects); + } + return true; + } + case GUI_ID_VOLUME_MUSIC_SB: + { + gui::IGUIElement *vsb = getElementFromId(GUI_ID_VOLUME_MUSIC_SB); + if(vsb != NULL && vsb->getType() == gui::EGUIET_SCROLL_BAR) { + m_data.volume_music = (float)((gui::IGUIScrollBar*)vsb)->getPos(); + config_set_int("client.sound.volume.music",m_data.volume_music); + } + return true; + } + } } if (event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED) { switch (event.GUIEvent.Caller->getID()) { diff --git a/src/guiSettingsMenu.h b/src/guiSettingsMenu.h index 8c6b908..3d87bd4 100644 --- a/src/guiSettingsMenu.h +++ b/src/guiSettingsMenu.h @@ -64,7 +64,9 @@ enum GUI_ID_PARTICLES_CB, GUI_ID_FULLSCREEN_CB, // sound - GUI_ID_VOLUME_SB, + GUI_ID_VOLUME_MASTER_SB, + GUI_ID_VOLUME_EFFECTS_SB, + GUI_ID_VOLUME_MUSIC_SB, // tabs GUI_ID_TAB_MAINMENU, GUI_ID_TAB_SETTINGS_CONTROLS, @@ -93,7 +95,9 @@ struct SettingsMenuData light_detail(3), hotbar(false), wield_index(false), - volume(0.0f), + volume_master(0.0f), + volume_effects(0.0f), + volume_music(0.0f), particles(true), fullscreen(false), texture_animation(true) @@ -113,7 +117,9 @@ struct SettingsMenuData bool trilinear_filter; bool hotbar; bool wield_index; - f32 volume; + f32 volume_master; + f32 volume_effects; + f32 volume_music; //int enable_shaders; bool particles; bool fullscreen; diff --git a/src/intl.c b/src/intl.c index 6fbc5d7..4afbc2e 100644 --- a/src/intl.c +++ b/src/intl.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ************************************************************************/ + +#include "common.h" #include "file.h" #include "crypto.h" diff --git a/src/intl.h b/src/intl.h index c51afa2..428235f 100644 --- a/src/intl.h +++ b/src/intl.h @@ -10,7 +10,7 @@ char* ngettext(const char* s1, const char* s2, int n); void intl_init(); #ifndef SERVER -// Initialise KeyNamesLang array +/* Initialise KeyNamesLang array */ void init_KeyNamesLang(); #endif diff --git a/src/main.cpp b/src/main.cpp index d93df9d..3dd7374 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,6 +79,7 @@ #if USE_FREETYPE #include "xCGUITTFont.h" #endif +#include "sound.h" // This makes textures ITextureSource *g_texturesource = NULL; @@ -826,8 +827,6 @@ int main(int argc, char *argv[]) // (for texture atlas making) init_mineral(); - ISoundManager *sound = NULL; - /* Game parameters */ @@ -849,6 +848,8 @@ int main(int argc, char *argv[]) // Run server dedicated_server_loop(server, kill); + config_save(NULL,NULL,NULL); + return 0; } @@ -862,8 +863,6 @@ int main(int argc, char *argv[]) u16 screenW = config_get_int("client.video.size.width"); u16 screenH = config_get_int("client.video.size.height"); - vlprintf(CN_INFO,"size %dx%d",screenW,screenH); - // bpp, fsaa, vsync bool vsync = config_get_bool("client.video.vsync"); @@ -989,7 +988,7 @@ int main(int argc, char *argv[]) drawLoadingScreen(device,narrow_to_wide(gettext("Setting Up Sound"))); #if USE_AUDIO == 1 - sound = createSoundManager(); + sound_init(); #endif /* @@ -1084,8 +1083,7 @@ int main(int argc, char *argv[]) -1, &g_menumgr, &menudata, - g_gamecallback, - sound + g_gamecallback ); menu->allowFocusRemoval(true); @@ -1105,7 +1103,7 @@ int main(int argc, char *argv[]) infostream<<"Created main menu"<playMusic("bg-mainmenu",true); + sound_play_music("bg-mainmenu",1.0); #endif while (device->run() && kill == false) { @@ -1126,7 +1124,7 @@ int main(int argc, char *argv[]) driver->endScene(); #if USE_AUDIO == 1 - sound->maintain(0.02); + sound_step(0.02,NULL,NULL,NULL); #endif // On some computers framerate doesn't seem to be @@ -1135,7 +1133,7 @@ int main(int argc, char *argv[]) } #if USE_AUDIO == 1 - sound->stopMusic(); + sound_stop_music(1.0); #endif // Break out of menu-game loop to shut down cleanly @@ -1210,7 +1208,7 @@ int main(int argc, char *argv[]) menu->allowFocusRemoval(true); #if USE_AUDIO == 1 - sound->playMusic("bg-charcreator",true); + sound_play_music("bg-charcreator",1.0); #endif while (device->run() && kill == false) { @@ -1225,7 +1223,7 @@ int main(int argc, char *argv[]) driver->endScene(); #if USE_AUDIO == 1 - sound->maintain(0.02); + sound_step(0.02,NULL,NULL,NULL); #endif // On some computers framerate doesn't seem to be @@ -1234,7 +1232,7 @@ int main(int argc, char *argv[]) } #if USE_AUDIO == 1 - sound->stopMusic(); + sound_stop_music(1.0); #endif menu->drop(); @@ -1253,8 +1251,7 @@ int main(int argc, char *argv[]) device, font, password, - error_message, - sound + error_message ); } //try @@ -1285,8 +1282,9 @@ int main(int argc, char *argv[]) delete input; - if (sound != NULL) - delete sound; +#if USE_AUDIO == 1 + sound_exit(); +#endif /* In the end, delete the Irrlicht device. diff --git a/src/map.cpp b/src/map.cpp index af963a7..2693521 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1693,6 +1693,8 @@ ServerMap::ServerMap(): char b[1024]; infostream<<__FUNCTION_NAME<::iterator i = m_sounds.begin(); i != m_sounds.end(); i++) { - g_sound->stopSound(i->second.id); - } +#if USE_AUDIO == 1 + for (std::map::iterator i = m_sounds.begin(); i != m_sounds.end(); i++) { + sound_stop_single(i->second.id); } +#endif } #endif diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index aeb9b72..85f0913 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -528,7 +528,9 @@ void MapBlockMesh::generate(MeshMakeData *data, v3s16 camera_offset, JMutex *mut MapNode n = data->m_vmanip.getNodeNoEx(data->m_blockpos_nodes+p); - if (g_sound) { + +#if USE_AUDIO == 1 + { std::string snd = content_features(n).sound_ambient; std::map::iterator i = data->m_sounds->find(p); if (snd != "") { @@ -576,6 +578,7 @@ void MapBlockMesh::generate(MeshMakeData *data, v3s16 camera_offset, JMutex *mut data->m_sounds->erase(i); } } +#endif if (data->light_detail > 1 && !selected.is_coloured) meshgen_preset_smooth_lights(data,p); switch (content_features(n).draw_type) { diff --git a/src/player.cpp b/src/player.cpp index 4cf42a9..8bdc9a3 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -760,12 +760,12 @@ void RemotePlayer::move(f32 dtime, Map &map, f32 pos_max_d) int frame = m_node->getFrameNr(); /* roughly sort of when a step sound should probably be heard, maybe */ if (frame == 218 || frame == 186 || frame == 209 || frame == 177) { - sound_playStep(&map,m_showpos,m_next_foot); + //sound_playStep(&map,m_showpos,m_next_foot); m_next_foot = !m_next_foot; } /* roughly sort of when a dig sound should probably be heard, maybe */ if (frame == 214 || frame == 205 || frame == 193) { - sound_playDig(m_pointed,m_showpos); + //sound_playDig(m_pointed,m_showpos); } if (m_anim_id == PLAYERANIM_DIE) { @@ -1224,7 +1224,8 @@ void LocalPlayer::applyControl(float dtime) }else if (m_energy < -0.1) { m_can_use_energy = false; m_energy = -0.1; - if (g_sound && m_low_energy_effect == 0) { +#if USE_AUDIO == 1 + if (m_low_energy_effect == 0) { if (m_character == "") m_character = std::string(PLAYER_DEFAULT_CHARDEF); Strfnd f(m_character); @@ -1232,14 +1233,18 @@ void LocalPlayer::applyControl(float dtime) std::string snd("low-energy-"); snd += gender; - m_low_energy_effect = g_sound->playSound(snd,true); + /* TODO: looping */ + m_low_energy_effect = sound_play_effect(snd.c_str(),1.0,NULL); } +#endif }else if (m_energy > 9.8) { m_can_use_energy = true; - if (g_sound && m_low_energy_effect) { - g_sound->stopSound(m_low_energy_effect); +#if USE_AUDIO == 1 + if (m_low_energy_effect) { + sound_stop_single(m_low_energy_effect); m_low_energy_effect = 0; } +#endif } if (energy_effectf > 0.0) diff --git a/src/server.cpp b/src/server.cpp index 11c82be..68a2569 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -48,7 +48,6 @@ #include "profiler.h" #include "log.h" #include "base64.h" -#include "sound.h" #include "http.h" #include "enchantment.h" #include "path.h" @@ -6038,11 +6037,6 @@ uint64_t Server::getPlayerPrivs(Player *player) return getPlayerAuthPrivs(playername); } -ISoundManager* Server::getSoundManager() -{ - return &dummySoundManager; -} - void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); diff --git a/src/server.h b/src/server.h index 9c5bd44..b829ba2 100644 --- a/src/server.h +++ b/src/server.h @@ -36,7 +36,6 @@ #include "inventory.h" #include "auth.h" #include "ban.h" -#include "sound.h" /* Some random functions @@ -465,7 +464,6 @@ public: // Envlock and conlock should be locked when calling this void notifyPlayer(const char *name, const std::wstring msg); void notifyPlayers(const std::wstring msg); - virtual ISoundManager* getSoundManager(); private: diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 0000000..d6c2106 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,647 @@ +/************************************************************************ +* sound.c +* voxelands - 3d voxel world sandbox game +* Copyright (C) Lisa 'darkrose' Milne 2017 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +************************************************************************/ + +#include "common.h" +#include "list.h" +#include "file.h" +#define _VL_SOUND_EXPOSE_INTERNAL +#include "sound.h" + +#include +#include +#include + +static struct { + int init; + float volume; + struct { + float volume; + float fade; + float fadev; + sound_t *sounds; + sound_instance_t *playing; + } effects; + struct { + float volume; + sound_t *sounds; + sound_instance_t *playing; + } music; + ALCdevice *device; + ALCcontext *context; +} sound_data = { + 0, + 0.5, + { + 0.5, + -1.0, + 1.0, + NULL, + NULL + }, + { + 0.5, + NULL, + NULL + }, + NULL, + NULL +}; + +/* initialise sound */ +int sound_init() +{ + /* initialise audio */ + sound_data.device = alcOpenDevice(NULL); + if (!sound_data.device) + return 1; + + sound_data.context = alcCreateContext(sound_data.device, NULL); + + if (!sound_data.context) { + alcCloseDevice(sound_data.device); + return 1; + } + + if (!alcMakeContextCurrent(sound_data.context) || (alcGetError(sound_data.device) != ALC_NO_ERROR)) { + alcDestroyContext(sound_data.context); + alcCloseDevice(sound_data.device); + return 1; + } + + alDistanceModel(AL_EXPONENT_DISTANCE); + alListenerf(AL_GAIN, 1.0); + + sound_data.init = 1; + + /* sounds must be mono sounds, stereo will not work right! + * exceptions: background music */ + + /* walking */ + /* CMT_DIRT */ + sound_load_effect("step_dirt.1.ogg","dirt-step-left"); + sound_load_effect("step_dirt.2.ogg","dirt-step-right"); + /* CMT_STONE */ + sound_load_effect("step_stone.1.ogg","stone-step-left"); + sound_load_effect("step_stone.2.ogg","stone-step-right"); + sound_load_effect("step_stone.3.ogg","stone-step-left"); + sound_load_effect("step_stone.4.ogg","stone-step-right"); + /* CMT_PLANT */ + sound_load_effect("step_plant.1.ogg","plant-step-left"); + sound_load_effect("step_plant.2.ogg","plant-step-right"); + /* CMT_LIQUID */ + sound_load_effect("step_liquid.1.ogg","liquid-step-left"); + sound_load_effect("step_liquid.2.ogg","liquid-step-right"); + /* CMT_WOOD */ + sound_load_effect("step_wood.1.ogg","wood-step-left"); + sound_load_effect("step_wood.2.ogg","wood-step-right"); + sound_load_effect("step_wood.3.ogg","wood-step-left"); + sound_load_effect("step_wood.4.ogg","wood-step-right"); + /* CMT_GLASS */ + sound_load_effect("step_glass.1.ogg","glass-step-left"); + sound_load_effect("step_glass.1.ogg","glass-step-right"); + /* special for grass */ + sound_load_effect("step_grass.1.ogg","grass-step-left"); + sound_load_effect("step_grass.2.ogg","grass-step-right"); + + /* digging */ + /* CMT_DIRT */ + sound_load_effect("dig_dirt.1.ogg","dirt-dig"); + /* CMT_STONE */ + sound_load_effect("dig_stone.1.ogg","stone-dig"); + /* CMT_PLANT */ + sound_load_effect("dig_plant.1.ogg","plant-dig"); + /* CMT_LIQUID */ + sound_load_effect("dig_liquid.1.ogg","liquid-dig"); + /* CMT_WOOD */ + sound_load_effect("dig_wood.1.ogg","wood-dig"); + /* CMT_GLASS */ + sound_load_effect("dig_glass.1.ogg","glass-dig"); + /* mobs */ + sound_load_effect("dig_mob.ogg","mob-dig"); + /* miss */ + sound_load_effect("dig_miss.ogg","miss-dig"); + + /* placing */ + sound_load_effect("place_node.1.ogg","place"); + sound_load_effect("place_node.2.ogg","place"); + sound_load_effect("place_node.3.ogg","place"); + /* CMT_DIRT */ + /* CMT_STONE */ + /* CMT_PLANT */ + /* CMT_LIQUID */ + sound_load_effect("place_liquid.1.ogg","liquid-place"); + /* CMT_WOOD */ + /* CMT_GLASS */ + + /* open formspec */ + sound_load_effect("open_menu.ogg","open-menu"); + sound_load_effect("open_book.ogg","open-book"); + sound_load_effect("open_chest.ogg","open-chest"); + + /* environment and node sounds */ + sound_load_effect("env_piston.ogg","env-piston"); + sound_load_effect("env_dooropen.ogg","env-dooropen"); + sound_load_effect("env_doorclose.ogg","env-doorclose"); + sound_load_effect("env_fire.ogg","env-fire"); + sound_load_effect("env_lava.ogg","env-lava"); + sound_load_effect("env_water.ogg","env-water"); + sound_load_effect("env_steam.ogg","env-steam"); + sound_load_effect("env_tnt.ogg","env-tnt"); + sound_load_effect("env_teleport.ogg","env-teleport"); + + /* mobs */ + sound_load_effect("mob_oerkki_spawn.ogg","mob-oerkki-spawn"); + sound_load_effect("mob_wolf_hit.ogg","mob-wolf-hit"); + sound_load_effect("mob_wolf_spawn.ogg","mob-wolf-spawn"); + sound_load_effect("mob_sheep_env.ogg","mob-sheep-env"); + sound_load_effect("mob_ducksheep_env.ogg","mob-ducksheep-env"); + sound_load_effect("mob_deer_env.ogg","mob-deer-env"); + + /* special */ + sound_load_effect("wield_item.ogg","wield"); + sound_load_effect("low_energy_F.ogg","low-energy-F"); + sound_load_effect("low_energy_M.ogg","low-energy-M"); + sound_load_effect("player_hurt_F.ogg","player-hurt-F"); + sound_load_effect("player_hurt_M.ogg","player-hurt-M"); + + /* use */ + sound_load_effect("use_eat.ogg","use-eat"); + sound_load_effect("use_drink.ogg","use-drink"); + + /* menu backgrounds */ + sound_load_music("bg_mainmenu.ogg","bg-mainmenu"); + sound_load_music("bg_charcreator.ogg","bg-charcreator"); + + return 0; +} + +/* exit sound */ +void sound_exit() +{ + if (!sound_data.init) + return; + + sound_stop(0); + alcMakeContextCurrent(NULL); + alcDestroyContext(sound_data.context); + alcCloseDevice(sound_data.device); + + sound_data.init = 0; + + /* TODO: unload sounds */ +} + +/* do stuff */ +void sound_process(float dtime) +{ + ALint state; + float v; + sound_instance_t *d; + sound_instance_t *i; + + /* factor = dtime / fade */ + + if (sound_data.effects.fade > -0.5) { + v = dtime/sound_data.effects.fade; + sound_data.effects.fadev -= v*sound_data.effects.volume*sound_data.volume; + if (sound_data.effects.fadev < 0.01) + sound_stop_effects(0); + } + i = sound_data.effects.playing; + while (i) { + alGetSourcei(i->id, AL_SOURCE_STATE, &state); + if (state != AL_PLAYING) { + d = i; + i = i->next; + sound_data.effects.playing = list_remove(&sound_data.effects.playing,d); + alDeleteSources(1, &d->id); + free(d); + continue; + } + if (i->fade > -0.5) { + if (i->fade > 0.01 && i->volume > 0.01) { + v = dtime/i->fade; + i->volume -= v*sound_data.music.volume*sound_data.volume; + if (i->volume > 0.01) + alSourcef(i->id, AL_GAIN, i->volume); + }else{ + d = i; + i = i->next; + sound_data.effects.playing = list_remove(&sound_data.effects.playing,d); + alDeleteSources(1, &d->id); + free(d); + continue; + } + } + if (sound_data.effects.fade > -0.5) + alSourcef(i->id, AL_GAIN, sound_data.effects.fadev); + i = i->next; + } +} + +/* */ +void sound_step(float dtime, v3_t *pos, v3_t *at, v3_t *up) +{ + float orientation[6] = {0.0,0.0,0.0,0.0,0.0,0.0}; + + sound_process(dtime); + + if (pos) { + alListenerfv(AL_POSITION, (float*)pos); + }else{ + alListener3f(AL_POSITION, 0.0,0.0,0.0); + } + + alListener3f(AL_VELOCITY, 0.0,0.0,0.0); + + if (at) { + orientation[0] = at->x; + orientation[1] = at->y; + orientation[2] = at->z; + } + + if (up) { + orientation[3] = up->x; + orientation[4] = up->y; + orientation[5] = up->z; + } + + alListenerfv(AL_ORIENTATION, orientation); +} + +/* get/set sound effect volume */ +float sound_volume_effects(float v) +{ + if (v > -0.5) { + if (v > 1.0) + v = 1.0; + sound_data.effects.volume = v; + + if (sound_data.init) { + float ev; + sound_instance_t *i = sound_data.effects.playing; + + ev = v*sound_data.volume; + + while (i) { + alSourcef(i->id, AL_GAIN, ev); + i = i->next; + } + } + } + return sound_data.effects.volume; +} + +/* get/set sound music volume */ +float sound_volume_music(float v) +{ + if (v > -0.5) { + if (v > 1.0) + v = 1.0; + sound_data.music.volume = v; + + if (sound_data.init && sound_data.music.playing) { + float ev; + + ev = v*sound_data.volume; + + alSourcef(sound_data.music.playing->id, AL_GAIN, ev); + + } + } + return sound_data.music.volume; +} + +/* get/set sound master volume */ +float sound_volume_master(float v) +{ + if (v > -0.5) { + if (v > 1.0) + v = 1.0; + sound_data.volume = v; + sound_volume_effects(sound_data.effects.volume); + sound_volume_music(sound_data.music.volume); + } + return sound_data.volume; +} + +/* load a sound identified by token from a file */ +static sound_t *sound_load(char* file, char* token) +{ + file_t *f; + sound_t *e = malloc(sizeof(sound_t)); + e->file = strdup(file); + e->token = strdup(token); + e->data = NULL; + e->d_len = 0; + + f = file_load("sound",file); + + if (sound_is_ogg(f)) { + if (sound_load_ogg(f,e)) + goto sound_load_fail; + }else if (sound_is_wav(f)) { + if (sound_load_wav(f,e)) + goto sound_load_fail; + }else{ + goto sound_load_fail; + } + + file_free(f); + + return e; + +sound_load_fail: + file_free(f); + free(e->file); + free(e->token); + if (e->data) + free(e->data); + free(e); + + vlprintf(CN_ERROR, "failed to load sound data for file '%s'",file); + + return NULL; +} + +/* load a sound effect identifed by token */ +int sound_load_effect(char* file, char* token) +{ + sound_t *e = sound_load(file,token); + if (!e) + return 1; + + sound_data.effects.sounds = list_push(&sound_data.effects.sounds,e); + + return 0; +} + +/* load music identifed by token */ +int sound_load_music(char* file, char* token) +{ + sound_t *e = sound_load(file,token); + if (!e) + return 1; + + sound_data.music.sounds = list_push(&sound_data.music.sounds,e); + + return 0; +} + +/* unload a sound effect */ +void sound_free_effect(char* token) +{ + sound_t *e = sound_data.effects.sounds; + + if (!e) + return; + + while (e) { + if (!strcmp(e->token,token)) + break; + e = e->next; + } + + if (!e) + return; + + sound_data.effects.sounds = list_remove(&sound_data.effects.sounds,e); + + alDeleteBuffers(1,&e->id); + + free(e->data); + free(e->file); + free(e->token); + free(e); +} + +/* unload a music */ +void sound_free_music(char* token) +{ + sound_t *e = sound_data.music.sounds; + if (!e) + return; + + while (e) { + if (!strcmp(e->token,token)) + break; + e = e->next; + } + + if (!e) + return; + + sound_data.music.sounds = list_remove(&sound_data.music.sounds,e); + + alDeleteBuffers(1,&e->id); + + free(e->data); + free(e->file); + free(e->token); + free(e); +} + +/* play sound effect */ +uint32_t sound_play_effect(char* token, float volume, v3_t *pos) +{ + sound_instance_t *i; + sound_t *e = sound_data.effects.sounds; + if (!sound_data.init || !e) + return 0; + + while (e) { + if (!strcmp(e->token,token)) + break; + e = e->next; + } + + if (!e) + return 0; + + i = malloc(sizeof(sound_instance_t)); + if (!i) + return 0; + + alGenSources(1, &i->id); + alSourcei(i->id, AL_BUFFER, e->id); + + i->volume = volume; + i->fade = -1.0; + + if (pos) { + alSourcei(i->id, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(i->id, AL_POSITION, pos->x, pos->y, pos->z); + alSourcef(i->id, AL_REFERENCE_DISTANCE, 30.0); + }else{ + alSourcei(i->id, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(i->id, AL_POSITION, 0, 0, 0); + } + + alSource3f(i->id, AL_VELOCITY, 0, 0, 0); + alSourcei(i->id, AL_LOOPING, AL_FALSE); + alSourcef(i->id, AL_GAIN, sound_data.effects.volume*sound_data.volume*volume); + alSourcePlay(i->id); + + if (alGetError() != AL_NO_ERROR) { + alDeleteSources(1, &i->id); + free(i); + return 0; + } + + sound_data.effects.playing = list_push(&sound_data.effects.playing,i); + + return i->id; +} + +/* play music */ +uint32_t sound_play_music(char* token, float volume) +{ + sound_t *e = sound_data.music.sounds; + if (!sound_data.init || !e) + return 0; + + while (e) { + if (!strcmp(e->token,token)) + break; + e = e->next; + } + + if (!e) + return 0; + + if (sound_data.music.playing) { + sound_data.effects.playing->fade = 1.0; + sound_data.effects.playing = list_push(&sound_data.effects.playing,sound_data.music.playing); + } + + sound_data.music.playing = malloc(sizeof(sound_instance_t)); + if (!sound_data.music.playing) + return 0; + + alGenSources(1, &sound_data.music.playing->id); + alSourcei(sound_data.music.playing->id, AL_BUFFER, e->id); + + sound_data.music.playing->volume = volume; + sound_data.music.playing->fade = -1.0; + + alSourcei(sound_data.music.playing->id, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(sound_data.music.playing->id, AL_POSITION, 0, 0, 0); + alSource3f(sound_data.music.playing->id, AL_VELOCITY, 0, 0, 0); + alSourcei(sound_data.music.playing->id, AL_LOOPING, AL_TRUE); + alSourcef(sound_data.music.playing->id, AL_GAIN, sound_data.music.volume*sound_data.volume*volume); + alSourcePlay(sound_data.music.playing->id); + + if (alGetError() != AL_NO_ERROR) { + alDeleteSources(1, &sound_data.music.playing->id); + free(sound_data.music.playing); + return 0; + } + + return sound_data.music.playing->id; +} + +/* stop sound effects, optionally fading out in fade seconds */ +void sound_stop_effects(int fade) +{ + if (fade) { + sound_data.effects.fade = fade; + sound_data.effects.fadev = sound_data.effects.volume; + }else{ + sound_instance_t *i = sound_data.effects.playing; + while (i) { + alSourceStop(i->id); + i = i->next; + } + sound_data.effects.fade = -1.0; + } +} + +/* stop music, optionally fading out in fade seconds */ +void sound_stop_music(int fade) +{ + if (!sound_data.music.playing) + return; + + if (!fade) + alSourceStop(sound_data.music.playing->id); + + sound_data.music.playing->fade = fade; + sound_data.music.playing->volume = sound_data.music.volume; + sound_data.effects.playing = list_push(&sound_data.effects.playing,sound_data.music.playing); + sound_data.music.playing = NULL; + +} + +void sound_stop_single(uint32_t id) +{ + sound_instance_t *i = sound_data.effects.playing; + while (i) { + if (i->id == id) { + alSourceStop(i->id); + break; + } + i = i->next; + } +} + +/* stop all sounds, optionally fading out in fade seconds */ +void sound_stop(int fade) +{ + sound_stop_music(fade); + sound_stop_effects(fade); +} + +/* command setter for sound effects volume */ +int sound_effects_setter(char* value) +{ + float vf; + int v = strtol(value,NULL,10); + vf = (float)v/100.0; + sound_volume_effects(vf); + + return 0; +} + +/* command setter for music volume */ +int sound_music_setter(char* value) +{ + float vf; + int v = strtol(value,NULL,10); + vf = (float)v/100.0; + sound_volume_music(vf); + + return 0; +} + +/* command setter for master volume */ +int sound_master_setter(char* value) +{ + int v = strtol(value,NULL,10); + if (v < 0) + v = 0; + if (v > 100) + v = 100; + + sound_data.volume = (float)v/100.0; + + sound_volume_effects(sound_data.effects.volume); + sound_volume_music(sound_data.music.volume); + + return 0; +} diff --git a/src/sound.h b/src/sound.h index 5ee7e7c..93c10c2 100644 --- a/src/sound.h +++ b/src/sound.h @@ -1,96 +1,73 @@ -/************************************************************************ -* Minetest-c55 -* Copyright (C) 2012 celeron55, Perttu Ahola -* -* sound.h -* voxelands - 3d voxel world sandbox game -* Copyright (C) Lisa 'darkrose' Milne 2014 -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see -* -* License updated from GPLv2 or later to GPLv3 or later by Lisa Milne -* for Voxelands. -************************************************************************/ +#ifndef _SOUND_H_ +#define _SOUND_H_ -#ifndef SOUND_HEADER -#define SOUND_HEADER +#include "common.h" +#include "nvp.h" -#include "common_irrlicht.h" -#include -#include -#include -#include "mapnode.h" +#include +#include +#include -class ISoundManager -{ -public: - virtual ~ISoundManager(){} +#ifdef __cplusplus +extern "C" { +#endif - // Multiple sounds can be loaded per name; when played, the sound - // should be chosen randomly from alternatives - // Return value determines success/failure - virtual bool loadSound(const std::string &name, const std::string &filepath, float gain=1.0) = 0; +typedef struct sound_s { + struct sound_s *prev; + struct sound_s *next; + char* file; + char* token; + ALenum format; + ALsizei freq; + ALuint id; + char* data; + int d_len; +} sound_t; - virtual void updateListener(v3f pos, v3f vel, v3f at, v3f up) = 0; - virtual void setListenerGain(float gain) = 0; +typedef struct sound_instance_s { + struct sound_instance_s *prev; + struct sound_instance_s *next; + ALuint id; + float volume; + float fade; +} sound_instance_t; - // playSound functions return -1 on failure, otherwise a handle to the - // sound. If name=="", call should be ignored without error. - virtual int playSound(const std::string &name, bool loop) = 0; - virtual int playSoundAt(const std::string &name, bool loop, v3f pos, float gain=1.0, bool queue=false) = 0; - virtual void stopSound(int sound) = 0; - virtual bool soundExists(int sound) = 0; +/* defined in sound.c */ +int sound_init(void); +void sound_exit(void); +void sound_step(float dtime, v3_t *pos, v3_t *at, v3_t *up); +int sound_load_effect(char* file, char* token); +int sound_load_music(char* file, char* token); +void sound_free_effect(char* token); +void sound_free_music(char* token); +uint32_t sound_play_effect(char* token, float volume, v3_t *pos); +uint32_t sound_play_music(char* token, float volume); +void sound_stop_effects(int fade); +void sound_stop_music(int fade); +void sound_stop_single(uint32_t id); +void sound_stop(int fade); +int sound_master_setter(char* value); +int sound_effects_setter(char* value); +int sound_music_setter(char* value); - virtual bool playMusic(const std::string &name, bool loop) = 0; - virtual void stopMusic() = 0; +#ifdef _VL_SOUND_EXPOSE_INTERNAL +/* defined in sound.c */ +void sound_process(float dtime); +float sound_volume_master(float v); +float sound_volume_effects(float v); +float sound_volume_music(float v); - virtual void updateSoundPosition(int sound, v3f pos) = 0; +/* defined in sound_ogg.c */ +int sound_is_ogg(file_t *f); +int sound_load_ogg(file_t *f, sound_t *e); - virtual void maintain(float dtime) = 0; -}; +/* defined in sound_wav.c */ +int sound_is_wav(file_t *f); +int sound_load_wav(file_t *f, sound_t *e); +#endif -class DummySoundManager: public ISoundManager -{ -public: - virtual bool loadSound(const std::string &name, const std::string &filepath, float gain) {return true;} - - void updateListener(v3f pos, v3f vel, v3f at, v3f up) {} - void setListenerGain(float gain) {} - - int playSound(const std::string &name, bool loop) {return 0;} - int playSoundAt(const std::string &name, bool loop, v3f pos, float gain, bool queue) {return 0;} - void stopSound(int sound) {} - bool soundExists(int sound) {return false;} - - bool playMusic(const std::string &name, bool loop) {return false;} - void stopMusic() {} - - void updateSoundPosition(int sound, v3f pos) {} - - void maintain(float dtime) {} -}; - -ISoundManager *createSoundManager(); -void init_sounds(ISoundManager *sound); - -class Map; - -// Global DummySoundManager singleton -extern DummySoundManager dummySoundManager; -extern ISoundManager *g_sound; - -void sound_playStep(Map *map, v3f pos, int foot, float gain=1.0); -void sound_playDig(content_t c, v3f pos); +#ifdef __cplusplus +} +#endif #endif diff --git a/src/sound_ogg.c b/src/sound_ogg.c new file mode 100644 index 0000000..3015ff3 --- /dev/null +++ b/src/sound_ogg.c @@ -0,0 +1,123 @@ +/************************************************************************ +* sound_ogg.c +* voxelands - 3d voxel world sandbox game +* Copyright (C) Lisa 'darkrose' Milne 2017 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +************************************************************************/ + +#include "common.h" +#include "sound.h" +#include "file.h" + +#include +#include + +#include + +static size_t sound_ogg_read(void* dst, size_t byte_size, size_t l, void* src) +{ + return file_read(src,dst,(l*byte_size)); +} + +static int sound_ogg_seek(void* src, ogg_int64_t offset, int origin) +{ + return file_seek(src,offset,origin); +} + +static int sound_ogg_close(void* src) +{ + return 0; +} + +static long sound_ogg_tell(void* src) +{ + return file_tell(src); +} + +/* is it an ogg? */ +int sound_is_ogg(file_t *f) +{ + int r; + OggVorbis_File oggfile; + ov_callbacks cb; + + cb.read_func = sound_ogg_read; + cb.close_func = sound_ogg_close; + cb.seek_func = sound_ogg_seek; + cb.tell_func = sound_ogg_tell; + + r = !ov_test_callbacks(f, &oggfile, NULL, 0, cb); + + if (r) + ov_clear(&oggfile); + + file_seek(f,0,SEEK_SET); + + return r; +} + +/* load an ogg file */ +int sound_load_ogg(file_t *f, sound_t *e) +{ + int endian = 0; + int bitStream; + int s; + char buff[30000]; + vorbis_info *ogginfo; + OggVorbis_File oggfile; + ov_callbacks cb; + + cb.read_func = sound_ogg_read; + cb.close_func = sound_ogg_close; + cb.seek_func = sound_ogg_seek; + cb.tell_func = sound_ogg_tell; + + if (ov_open_callbacks(f, &oggfile, NULL, 0, cb)) + return 1; + + ogginfo = ov_info(&oggfile, -1); + + /* always use 16-bit samples */ + if (ogginfo->channels == 1) { + e->format = AL_FORMAT_MONO16; + }else{ + e->format = AL_FORMAT_STEREO16; + } + + e->freq = ogginfo->rate; + + do{ + s = ov_read(&oggfile, buff, 30000, endian, 2, 1, &bitStream); + if (s < 0) { + ov_clear(&oggfile); + return 1; + } + + e->data = realloc(e->data,e->d_len+s); + memcpy(e->data+e->d_len,buff,s); + e->d_len += s; + } while (s > 0); + + alGenBuffers(1, &e->id); + alBufferData(e->id, e->format, e->data, e->d_len, e->freq); + + + if (alGetError() != AL_NO_ERROR) + return 1; + + ov_clear(&oggfile); + + return 0; +} diff --git a/src/sound_wav.c b/src/sound_wav.c new file mode 100644 index 0000000..c5ca319 --- /dev/null +++ b/src/sound_wav.c @@ -0,0 +1,105 @@ +/************************************************************************ +* sound_wav.c +* voxelands - 3d voxel world sandbox game +* Copyright (C) Lisa 'darkrose' Milne 2017 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +************************************************************************/ + +#include "common.h" +#include "sound.h" +#include "file.h" + +#include + +typedef struct wav_file_header_s { + char riff[4]; /* 'RIFF' */ + int size; + char wave[4]; /* 'WAVE' */ + char fmt[4]; /* 'fmt ' */ + int f_len; + short int f_tag; +} __attribute__((packed)) wav_file_header_t; + +typedef struct wav_format_header_s { + short int channels; + int freq; + int bytes_per_second; + short int block_align; + short int bps; + char data[4]; /* 'data' */ + int d_len; +} __attribute__((packed)) wav_format_header_t; + +/* is it a wav file? */ +int sound_is_wav(file_t *f) +{ + int r = 0; + wav_file_header_t h; + + file_read(f,&h,sizeof(wav_file_header_t)); + + if (!strncmp("RIFF",h.riff,4) && !strncmp("WAVE",h.wave,4)) + r = 1; + + file_seek(f,0,SEEK_SET); + + return r; +} + +/* load a wav file */ +int sound_load_wav(file_t *f, sound_t *e) +{ + wav_file_header_t h; + wav_format_header_t fmt; + unsigned char* data; + + file_read(f,&h,sizeof(wav_file_header_t)); + file_read(f,&fmt,sizeof(wav_format_header_t)); + data = file_get(f); + + if (h.f_tag != 1) { + return 1; + }else if (fmt.bps == 8) { + if (fmt.channels == 1) { + e->format = AL_FORMAT_MONO8; + }else{ + e->format = AL_FORMAT_STEREO8; + } + }else if (fmt.bps == 16) { + if (fmt.channels == 1) { + e->format = AL_FORMAT_MONO16; + }else{ + e->format = AL_FORMAT_STEREO16; + } + }else{ + return 1; + } + + e->freq = fmt.freq; + + e->d_len = fmt.d_len; + e->data = malloc(e->d_len); + + memcpy(e->data,data,e->d_len); + + alGenBuffers(1, &e->id); + alBufferData(e->id, e->format, e->data, e->d_len, e->freq); + + + if (alGetError() != AL_NO_ERROR) + return 1; + + return 0; +} diff --git a/src/thread.c b/src/thread.c index f4461f7..bb8d8cc 100644 --- a/src/thread.c +++ b/src/thread.c @@ -17,6 +17,7 @@ * along with this program. If not, see ************************************************************************/ +#include "common.h" #include "thread.h" #include "list.h" #include "array.h"