From 20afba1adc84dd0e859605250c5a44a111045c2b Mon Sep 17 00:00:00 2001 From: Thorbjørn Lindeijer Date: Sat, 18 Feb 2012 22:47:30 +0100 Subject: Added notification sound on receiving whisper One of the sound channels is reserved for notification sounds, of which the volume can be configured separately. Currently, the only notification sound that is played is for receiving whispers. That can be extended later. The newmessage.ogg sound used currently is the one for receiving a message with the Psi instant messenger. Parts of this patch are based on the new message notification in ManaPlus. Reviewed-by: Erik Schilling --- AUTHORS | 4 ++++ data/CMakeLists.txt | 1 + data/sfx/CMakeLists.txt | 1 + data/sfx/system/CMakeLists.txt | 5 +++++ data/sfx/system/newmessage.ogg | Bin 0 -> 8194 bytes src/client.cpp | 3 ++- src/client.h | 9 +++++++++ src/defaults.cpp | 1 + src/gui/gui.cpp | 3 ++- src/gui/setup_audio.cpp | 32 +++++++++++++++++++++++++------- src/gui/setup_audio.h | 18 ++++++++++++------ src/gui/widgets/chattab.cpp | 23 ++++++++++++++++++++--- src/gui/widgets/chattab.h | 9 +++++++++ src/gui/widgets/whispertab.h | 3 +++ src/resources/soundeffect.cpp | 4 ++-- src/resources/soundeffect.h | 3 ++- src/sound.cpp | 29 +++++++++++++++++++++++++++++ src/sound.h | 9 +++++++++ 18 files changed, 136 insertions(+), 21 deletions(-) create mode 100644 data/sfx/CMakeLists.txt create mode 100644 data/sfx/system/CMakeLists.txt create mode 100644 data/sfx/system/newmessage.ogg diff --git a/AUTHORS b/AUTHORS index b830e054..2efa90bf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -75,3 +75,7 @@ Jean-Francois Lampron Rodney Dawes Ultramichy Zuzanna K. Filutowska + +== Sound files == + +data/sfx/system/newmessage.ogg (Psi-IM, GPL) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 4aa0cdd5..e5dd528c 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -4,3 +4,4 @@ ADD_SUBDIRECTORY(fonts) ADD_SUBDIRECTORY(graphics) ADD_SUBDIRECTORY(help) ADD_SUBDIRECTORY(icons) +ADD_SUBDIRECTORY(sfx) diff --git a/data/sfx/CMakeLists.txt b/data/sfx/CMakeLists.txt new file mode 100644 index 00000000..e006c71f --- /dev/null +++ b/data/sfx/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(system) diff --git a/data/sfx/system/CMakeLists.txt b/data/sfx/system/CMakeLists.txt new file mode 100644 index 00000000..b19c3e06 --- /dev/null +++ b/data/sfx/system/CMakeLists.txt @@ -0,0 +1,5 @@ +SET(FILES + newmessage.ogg + ) + +INSTALL(FILES ${FILES} DESTINATION ${DATA_DIR}/sfx/system) diff --git a/data/sfx/system/newmessage.ogg b/data/sfx/system/newmessage.ogg new file mode 100644 index 00000000..69b996f7 Binary files /dev/null and b/data/sfx/system/newmessage.ogg differ diff --git a/src/client.cpp b/src/client.cpp index 5a9cc726..28affce6 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -380,6 +380,7 @@ Client::Client(const Options &options): sound.init(); sound.setSfxVolume(config.getIntValue("sfxVolume")); + sound.setNotificationsVolume(config.getIntValue("notificationsVolume")); sound.setMusicVolume(config.getIntValue("musicVolume")); } catch (const char *err) @@ -541,7 +542,7 @@ int Client::exec() lastTickTime = tick_time; // Update the screen when application is active, delay otherwise. - if (SDL_GetAppState() & SDL_APPACTIVE) + if (isActive()) { frame_count++; gui->draw(); diff --git a/src/client.h b/src/client.h index 2ee6764c..4ad5562d 100644 --- a/src/client.h +++ b/src/client.h @@ -214,6 +214,15 @@ public: */ void videoResized(int width, int height); + static bool isActive() + { return SDL_GetAppState() & SDL_APPACTIVE; } + + static bool hasInputFocus() + { return SDL_GetAppState() & SDL_APPINPUTFOCUS; } + + static bool hasMouseFocus() + { return SDL_GetAppState() & SDL_APPMOUSEFOCUS; } + private: void initRootDir(); void initHomeDir(); diff --git a/src/defaults.cpp b/src/defaults.cpp index fea7c435..6c75797d 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -85,6 +85,7 @@ DefaultsData* getConfigDefaults() AddDEF(configData, "hwaccel", false); AddDEF(configData, "sound", false); AddDEF(configData, "sfxVolume", 100); + AddDEF(configData, "notificationsVolume", 100); AddDEF(configData, "musicVolume", 60); AddDEF(configData, "remember", false); AddDEF(configData, "username", ""); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2f24d009..78fc42fb 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -29,6 +29,7 @@ #include "gui/widgets/window.h" #include "gui/widgets/windowcontainer.h" +#include "client.h" #include "configuration.h" #include "eventlistener.h" #include "graphics.h" @@ -204,7 +205,7 @@ void Gui::draw() int mouseX, mouseY; Uint8 button = SDL_GetMouseState(&mouseX, &mouseY); - if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS || button & SDL_BUTTON(1)) + if ((Client::hasMouseFocus() || button & SDL_BUTTON(1)) && mCustomCursor && mMouseCursorAlpha > 0.0f) { diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index c43210d0..69ee3dc3 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -37,31 +37,38 @@ Setup_Audio::Setup_Audio(): mMusicVolume(config.getIntValue("musicVolume")), mSfxVolume(config.getIntValue("sfxVolume")), + mNotificationsVolume(config.getIntValue("notificationsVolume")), mSoundEnabled(config.getBoolValue("sound")), mDownloadEnabled(config.getBoolValue("download-music")), mSoundCheckBox(new CheckBox(_("Sound"), mSoundEnabled)), mDownloadMusicCheckBox(new CheckBox(_("Download music"), mDownloadEnabled)), mSfxSlider(new Slider(0, sound.getMaxVolume())), + mNotificationsSlider(new Slider(0, sound.getMaxVolume())), mMusicSlider(new Slider(0, sound.getMaxVolume())) { setName(_("Audio")); setDimension(gcn::Rectangle(0, 0, 250, 200)); gcn::Label *sfxLabel = new Label(_("Sfx volume")); + gcn::Label *notificationsLabel = new Label(_("Notifications volume")); gcn::Label *musicLabel = new Label(_("Music volume")); mSfxSlider->setActionEventId("sfx"); + mNotificationsSlider->setActionEventId("notifications"); mMusicSlider->setActionEventId("music"); mSfxSlider->addActionListener(this); + mNotificationsSlider->addActionListener(this); mMusicSlider->addActionListener(this); mSoundCheckBox->setPosition(10, 10); mSfxSlider->setValue(mSfxVolume); + mNotificationsSlider->setValue(mNotificationsVolume); mMusicSlider->setValue(mMusicVolume); mSfxSlider->setWidth(90); + mNotificationsSlider->setWidth(90); mMusicSlider->setWidth(90); // Do the layout @@ -71,9 +78,11 @@ Setup_Audio::Setup_Audio(): place(0, 0, mSoundCheckBox); place(0, 1, mSfxSlider); place(1, 1, sfxLabel); - place(0, 2, mMusicSlider); - place(1, 2, musicLabel); - place(0, 3, mDownloadMusicCheckBox); + place(0, 2, mNotificationsSlider); + place(1, 2, notificationsLabel); + place(0, 3, mMusicSlider); + place(1, 3, musicLabel); + place(0, 4, mDownloadMusicCheckBox); setDimension(gcn::Rectangle(0, 0, 370, 280)); } @@ -83,6 +92,7 @@ void Setup_Audio::apply() mSoundEnabled = mSoundCheckBox->isSelected(); mDownloadEnabled = mDownloadMusicCheckBox->isSelected(); mSfxVolume = config.getIntValue("sfxVolume"); + mNotificationsVolume = config.getIntValue("sfxVolume"); mMusicVolume = config.getIntValue("musicVolume"); config.setValue("sound", mSoundEnabled); @@ -134,12 +144,20 @@ void Setup_Audio::action(const gcn::ActionEvent &event) { if (event.getId() == "sfx") { - config.setValue("sfxVolume", (int) mSfxSlider->getValue()); - sound.setSfxVolume((int) mSfxSlider->getValue()); + int volume = (int) mSfxSlider->getValue(); + config.setValue("sfxVolume", volume); + sound.setSfxVolume(volume); + } + else if (event.getId() == "notifications") + { + int volume = (int) mNotificationsSlider->getValue(); + config.setValue("notificationsVolume", volume); + sound.setNotificationsVolume(volume); } else if (event.getId() == "music") { - config.setValue("musicVolume", (int) mMusicSlider->getValue()); - sound.setMusicVolume((int) mMusicSlider->getValue()); + int volume = (int) mMusicSlider->getValue(); + config.setValue("musicVolume", volume); + sound.setMusicVolume(volume); } } diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h index 5477eaad..ac81bdb7 100644 --- a/src/gui/setup_audio.h +++ b/src/gui/setup_audio.h @@ -39,11 +39,17 @@ class Setup_Audio : public SetupTab, public gcn::ActionListener void action(const gcn::ActionEvent &event); private: - int mMusicVolume, mSfxVolume; - bool mSoundEnabled, mDownloadEnabled; - - gcn::CheckBox *mSoundCheckBox, *mDownloadMusicCheckBox; - gcn::Slider *mSfxSlider, *mMusicSlider; + int mMusicVolume; + int mSfxVolume; + int mNotificationsVolume; + bool mSoundEnabled; + bool mDownloadEnabled; + + gcn::CheckBox *mSoundCheckBox; + gcn::CheckBox *mDownloadMusicCheckBox; + gcn::Slider *mSfxSlider; + gcn::Slider *mNotificationsSlider; + gcn::Slider *mMusicSlider; }; -#endif +#endif // GUI_SETUP_AUDIO_H diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index 8642be69..1979ecbd 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -23,9 +23,11 @@ #include "actorspritemanager.h" #include "chatlogger.h" +#include "client.h" #include "commandhandler.h" #include "configuration.h" #include "localplayer.h" +#include "sound.h" #include "gui/gui.h" #include "gui/recorder.h" @@ -237,10 +239,20 @@ void ChatTab::chatLog(std::string line, Own own, bool ignoreRecord) } mScrollArea->logic(); + chatWindow->mRecorder->record(line.substr(3)); - if (this != getTabbedArea()->getSelectedTab() && - own != BY_PLAYER) - setFlash(true); + + if (own != BY_PLAYER) + { + bool currentTab = getTabbedArea()->getSelectedTab() == this; + + if (!currentTab) + setFlash(true); + + if (!(currentTab && Client::hasInputFocus()) && own != BY_SERVER) + if (checkNotify(own)) + sound.playNotification("system/newmessage.ogg"); + } } void ChatTab::chatLog(const std::string &nick, const std::string &msg) @@ -318,6 +330,11 @@ void ChatTab::handleCommand(const std::string &msg) commandHandler->handleCommand(msg, this); } +bool ChatTab::checkNotify(Own own) const +{ + return own == ACT_WHISPER; +} + void ChatTab::getAutoCompleteList(std::vector &names) const { actorSpriteManager->getPlayerNPCNameLister()->getAutoCompleteList(names); diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h index 3796c37b..200ad55a 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -114,6 +114,15 @@ class ChatTab : public Tab, public AutoCompleteLister, public EventListener virtual void handleCommand(const std::string &msg); + /** + * Returns whether a notify sound may be played for the given type of + * message. By default, only returns true for inline whispers. + * + * Is never called for server-messages or when the window has focus + * and this is the current tab. + */ + virtual bool checkNotify(Own own) const; + /** * Adapts the text format to the current gui opacity, * for better readability. diff --git a/src/gui/widgets/whispertab.h b/src/gui/widgets/whispertab.h index e88d084b..a0dcfc14 100644 --- a/src/gui/widgets/whispertab.h +++ b/src/gui/widgets/whispertab.h @@ -57,6 +57,9 @@ class WhisperTab : public ChatTab void handleCommand(const std::string &msg); + bool checkNotify(Own) const + { return true; } + private: std::string mNick; }; diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp index 91ee1fde..d1b0227b 100644 --- a/src/resources/soundeffect.cpp +++ b/src/resources/soundeffect.cpp @@ -44,9 +44,9 @@ Resource *SoundEffect::load(SDL_RWops *rw) } } -bool SoundEffect::play(int loops, int volume) +bool SoundEffect::play(int loops, int volume, int channel) { Mix_VolumeChunk(mChunk, volume); - return Mix_PlayChannel(-1, mChunk, loops) != -1; + return Mix_PlayChannel(channel, mChunk, loops) != -1; } diff --git a/src/resources/soundeffect.h b/src/resources/soundeffect.h index dee8f551..decc60a0 100644 --- a/src/resources/soundeffect.h +++ b/src/resources/soundeffect.h @@ -53,11 +53,12 @@ class SoundEffect : public Resource * * @param loops Number of times to repeat the playback. * @param volume Sample playback volume. + * @param channel Sample playback channel. * * @return true if the playback started properly * false otherwise. */ - virtual bool play(int loops, int volume); + bool play(int loops, int volume, int channel = -1); protected: SoundEffect(Mix_Chunk *soundEffect): mChunk(soundEffect) {} diff --git a/src/sound.cpp b/src/sound.cpp index e8348a40..1af1f136 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -31,6 +31,10 @@ #include "resources/resourcemanager.h" #include "resources/soundeffect.h" +enum { + CHANNEL_NOTIFICATIONS = 0 +}; + /** * This will be set to true, when a music can be freed after a fade out * Currently used by fadeOutCallBack() @@ -49,6 +53,7 @@ static void fadeOutCallBack() Sound::Sound(): mInstalled(false), mSfxVolume(100), + mNotificationsVolume(100), mMusicVolume(60), mMusic(NULL) { @@ -90,8 +95,10 @@ void Sound::init() } Mix_AllocateChannels(16); + Mix_ReserveChannels(1); // reserve one channel for notification sounds Mix_VolumeMusic(mMusicVolume); Mix_Volume(-1, mSfxVolume); + Mix_Volume(CHANNEL_NOTIFICATIONS, mNotificationsVolume); info(); @@ -154,7 +161,18 @@ void Sound::setSfxVolume(int volume) mSfxVolume = volume; if (mInstalled) + { Mix_Volume(-1, mSfxVolume); + Mix_Volume(CHANNEL_NOTIFICATIONS, mNotificationsVolume); + } +} + +void Sound::setNotificationsVolume(int volume) +{ + mNotificationsVolume = volume; + + if (mInstalled) + Mix_Volume(CHANNEL_NOTIFICATIONS, mNotificationsVolume); } static Music *loadMusic(const std::string &fileName) @@ -281,6 +299,17 @@ void Sound::playSfx(const std::string &path, int x, int y) } } +void Sound::playNotification(const std::string &path) +{ + const std::string fullPath = paths.getValue("sfx", "sfx/") + path; + + ResourceManager *resman = ResourceManager::getInstance(); + if (SoundEffect *sample = resman->getSoundEffect(fullPath)) + { + sample->play(0, 128, CHANNEL_NOTIFICATIONS); + } +} + void Sound::close() { if (!mInstalled) diff --git a/src/sound.h b/src/sound.h index dd368f84..180bca62 100644 --- a/src/sound.h +++ b/src/sound.h @@ -92,6 +92,7 @@ class Sound void setMusicVolume(int volume); void setSfxVolume(int volume); + void setNotificationsVolume(int volume); /** * Plays a sound at the specified location. @@ -102,6 +103,13 @@ class Sound */ void playSfx(const std::string &path, int x = 0, int y = 0); + /** + * Plays a sound on the notification channel. + * + * @param path The resource path to the sound file. + */ + void playNotification(const std::string &path); + /** * The sound logic. * Currently used to check whether the music file can be freed after @@ -125,6 +133,7 @@ class Sound bool mInstalled; int mSfxVolume; + int mNotificationsVolume; int mMusicVolume; std::string mCurrentMusicFile; -- cgit v1.2.3-70-g09d2