diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5d16b11dc..d876b66f6 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -260,6 +260,7 @@ set(viewer_SOURCE_FILES llfloatertos.cpp llfloaterurldisplay.cpp llfloaterurlentry.cpp + llfloatervoiceeffect.cpp llfloaterwater.cpp llfloaterwebcontent.cpp llfloaterwindlight.cpp @@ -765,6 +766,7 @@ set(viewer_HEADER_FILES llfloatertos.h llfloaterurldisplay.h llfloaterurlentry.h + llfloatervoiceeffect.h llfloaterwater.h llfloaterwebcontent.h llfloaterwindlight.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 309252bef..44dea9cd1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7427,6 +7427,22 @@ This should be as low as possible, but too low may break functionality Value -1 + FloaterVoiceEffectRect + + Comment + Rectangle for voice morpher floater + Persist + 1 + Type + Rect + Value + + 0 + 300 + 360 + 0 + + FloaterWorldMapRect2 Comment diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp new file mode 100644 index 000000000..415798086 --- /dev/null +++ b/indra/newview/llfloatervoiceeffect.cpp @@ -0,0 +1,318 @@ +/** + * @file llfloatervoiceeffect.cpp + * @author Aimee + * @brief Selection and preview of voice effect. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatervoiceeffect.h" + +#include "llscrolllistctrl.h" +#include "lltexteditor.h" // For linked text hack +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llweb.h" + +LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key) + : LLFloater(/*key*/) +{ + mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this)); + mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); + mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this)); + mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this)); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_voice_effect.xml"); +} + +// virtual +LLFloaterVoiceEffect::~LLFloaterVoiceEffect() +{ + if(LLVoiceClient::instanceExists()) + { + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->removeObserver(this); + } + } +} + +// virtual +BOOL LLFloaterVoiceEffect::postBuild() +{ + setDefaultBtn("record_btn"); + getChild("record_btn")->setFocus(true); + + // Singu Note: Here we must hack together a linked piece of text + if (LLTextEditor* editor = getChild("voice_morphing_link")) + { + editor->setParseHTML(true); // For some reason, adding style doesn't work unless this is true. + const std::string text = editor->getValue(); + editor->clear(); + LLStyleSP link(new LLStyle); + link->setLinkHREF(LLTrans::getString("voice_morphing_url")); + link->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + editor->appendStyledText(text, false, false, link); + } + + mVoiceEffectList = getChild("voice_effect_list"); + if (mVoiceEffectList) + { + mVoiceEffectList->setCommitCallback(boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); +// mVoiceEffectList->setDoubleClickCallback(boost::bind(&LLFloaterVoiceEffect::onClickActivate, this)); + } + + return TRUE; +} + +// virtual +void LLFloaterVoiceEffect::onOpen() +{ + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->addObserver(this); + + // Disconnect from the current voice channel ready to record a voice sample for previewing + effect_interface->enablePreviewBuffer(true); + } + + refreshEffectList(); + updateControls(); +} + +// virtual +void LLFloaterVoiceEffect::onClose(bool app_quitting) +{ + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->enablePreviewBuffer(false); + } + setVisible(false); +} + +void LLFloaterVoiceEffect::refreshEffectList() +{ + if (!mVoiceEffectList) + { + return; + } + + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (!effect_interface) + { + mVoiceEffectList->setEnabled(false); + return; + } + + LL_DEBUGS("Voice")<< "Rebuilding Voice Morph list."<< LL_ENDL; + + // Preserve selected items and scroll position + S32 scroll_pos = mVoiceEffectList->getScrollPos(); + uuid_vec_t selected_items; + std::vector items = mVoiceEffectList->getAllSelected(); + for(std::vector::const_iterator it = items.begin(); it != items.end(); it++) + { + selected_items.push_back((*it)->getUUID()); + } + + mVoiceEffectList->deleteAllItems(); + + { + // Add the "No Voice Morph" entry + LLSD element; + + element["id"] = LLUUID::null; + element["columns"][NAME_COLUMN]["column"] = "name"; + element["columns"][NAME_COLUMN]["value"] = getString("no_voice_effect"); + element["columns"][NAME_COLUMN]["font"] = "SANSSERIF"; + element["columns"][NAME_COLUMN]["font-style"] = "BOLD"; + + /*LLScrollListItem* sl_item =*/ mVoiceEffectList->addElement(element, ADD_BOTTOM); + /* Singu Note: Ours works + // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :( + if(sl_item) + { + ((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(LLFontGL::BOLD); + } + */ + } + + // Add each Voice Morph template, if there are any (template list includes all usable effects) + const voice_effect_list_t& template_list = effect_interface->getVoiceEffectTemplateList(); + if (!template_list.empty()) + { + for (voice_effect_list_t::const_iterator it = template_list.begin(); it != template_list.end(); ++it) + { + const LLUUID& effect_id = it->second; + + std::string localized_effect = "effect_" + it->first; + std::string effect_name = hasString(localized_effect) ? getString(localized_effect) : it->first; // XML contains localized effects names + + LLSD effect_properties = effect_interface->getVoiceEffectProperties(effect_id); + + // Tag the active effect. + if (effect_id == LLVoiceClient::instance().getVoiceEffectDefault()) + { + effect_name += " " + getString("active_voice_effect"); + } + + // Tag available effects that are new this session + if (effect_properties["is_new"].asBoolean()) + { + effect_name += " " + getString("new_voice_effect"); + } + + LLDate expiry_date = effect_properties["expiry_date"].asDate(); + bool is_template_only = effect_properties["template_only"].asBoolean(); + + std::string font_style = "NORMAL"; + if (!is_template_only) + { + font_style = "BOLD"; + } + + LLSD element; + element["id"] = effect_id; + + element["columns"][NAME_COLUMN]["column"] = "name"; + element["columns"][NAME_COLUMN]["value"] = effect_name; + element["columns"][NAME_COLUMN]["font"] = "SANSSERIF"; + element["columns"][NAME_COLUMN]["font-style"] = font_style; + + element["columns"][1]["column"] = "expires"; + if (!is_template_only) + { + element["columns"][DATE_COLUMN]["value"] = expiry_date; + element["columns"][DATE_COLUMN]["type"] = "date"; + } + else { + element["columns"][DATE_COLUMN]["value"] = getString("unsubscribed_voice_effect"); + } + element["columns"][DATE_COLUMN]["font"] = "SANSSERIF"; + element["columns"][DATE_COLUMN]["font-style"] = "NORMAL"; + + /*LLScrollListItem* sl_item =*/ mVoiceEffectList->addElement(element, ADD_BOTTOM); + /* Singu Note: Ours works + // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :( + if(sl_item) + { + LLFontGL::StyleFlags style = is_template_only ? LLFontGL::NORMAL : LLFontGL::BOLD; + LLScrollListText* slt = dynamic_cast(sl_item->getColumn(0)); + llassert(slt); + if (slt) + { + slt->setFontStyle(style); + } + } + */ + } + } + + // Re-select items that were selected before, and restore the scroll position + for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++) + { + mVoiceEffectList->selectByID(*it); + } + mVoiceEffectList->setScrollPos(scroll_pos); + mVoiceEffectList->setEnabled(true); +} + +void LLFloaterVoiceEffect::updateControls() +{ + bool recording = false; + + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + recording = effect_interface->isPreviewRecording(); + } + + getChild("record_btn")->setVisible(!recording); + getChild("record_stop_btn")->setVisible(recording); +} + +// virtual +void LLFloaterVoiceEffect::onVoiceEffectChanged(bool effect_list_updated) +{ + if (effect_list_updated) + { + refreshEffectList(); + } + updateControls(); +} + +void LLFloaterVoiceEffect::onClickRecord() +{ + LL_DEBUGS("Voice") << "Record clicked" << LL_ENDL; + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->recordPreviewBuffer(); + } + updateControls(); +} + +void LLFloaterVoiceEffect::onClickPlay() +{ + LL_DEBUGS("Voice") << "Play clicked" << LL_ENDL; + if (!mVoiceEffectList) + { + return; + } + + const LLUUID& effect_id = mVoiceEffectList->getCurrentID(); + + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->playPreviewBuffer(effect_id); + } + updateControls(); +} + +void LLFloaterVoiceEffect::onClickStop() +{ + LL_DEBUGS("Voice") << "Stop clicked" << LL_ENDL; + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface) + { + effect_interface->stopPreviewBuffer(); + } + updateControls(); +} + +void LLFloaterVoiceEffect::onClickActivate() +{ + LL_DEBUGS("Voice") << "Activate clicked" << LL_ENDL; + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + if (effect_interface && mVoiceEffectList) + { + //effect_interface->setVoiceEffect(mVoiceEffectList->getCurrentID()); // Singu Note: This would return early, since we're disconnected from voice, just set the string and refresh list + gSavedPerAccountSettings.setString("VoiceEffectDefault", mVoiceEffectList->getCurrentID().asString()); + refreshEffectList(); + } +} + diff --git a/indra/newview/llfloatervoiceeffect.h b/indra/newview/llfloatervoiceeffect.h new file mode 100644 index 000000000..9bee8937c --- /dev/null +++ b/indra/newview/llfloatervoiceeffect.h @@ -0,0 +1,74 @@ +/** + * @file llfloatervoiceeffect.h + * @author Aimee + * @brief Selection and preview of voice effects. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERVOICEEFFECT_H +#define LL_LLFLOATERVOICEEFFECT_H + +#include "llfloater.h" +#include "llvoiceclient.h" + +class LLButton; +class LLScrollListCtrl; + +class LLFloaterVoiceEffect + : public LLFloater + , public LLVoiceEffectObserver + , public LLFloaterSingleton +{ +public: + LOG_CLASS(LLFloaterVoiceEffect); + + LLFloaterVoiceEffect(const LLSD& key); + virtual ~LLFloaterVoiceEffect(); + + virtual BOOL postBuild(); + virtual void onOpen(); + virtual void onClose(bool app_quitting); + +private: + enum ColumnIndex + { + NAME_COLUMN = 0, + DATE_COLUMN = 1, + }; + + void refreshEffectList(); + void updateControls(); + + /// Called by voice effect provider when voice effect list is changed. + virtual void onVoiceEffectChanged(bool effect_list_updated); + + void onClickRecord(); + void onClickPlay(); + void onClickStop(); + void onClickActivate(); + + LLUUID mSelectedID; + LLScrollListCtrl* mVoiceEffectList; +}; + +#endif diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2f6c73c0e..bdd452de3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -109,6 +109,7 @@ #include "llfloaterteleporthistory.h" #include "llfloatertest.h" #include "llfloatertools.h" +#include "llfloatervoiceeffect.h" #include "llfloaterwater.h" #include "llfloaterwebcontent.h" #include "llfloaterwindlight.h" @@ -6383,6 +6384,7 @@ struct MenuFloaterDict : public LLSingleton registerFloater ("script info"); registerFloater ("stat bar"); registerFloater ("teleport history"); + registerFloater ("voice effect"); registerFloater ("pathfinding_characters"); registerFloater ("pathfinding_linksets"); diff --git a/indra/newview/skins/default/xui/en-us/floater_voice_effect.xml b/indra/newview/skins/default/xui/en-us/floater_voice_effect.xml new file mode 100644 index 000000000..d625ffcc8 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_voice_effect.xml @@ -0,0 +1,180 @@ + + + + (No Voice Morph) + + + (Active) + + + (Unsubscribed) + + + (New!) + + + + Arena + Beast + Buff + Buzz + Camille + Creepy + CreepyBot + Cyber + DeepBot + Demon + Female Elf + Flirty + Foxy + Halloween_2010_Bonus + Helium + Husky + Husky Whisper + Intercom + Julia + Lo Lilt + Macho + Micro + Mini + Model + Nano + Nightmare + PopBot + Rachel + Radio + Robot + Roxanne + Rumble + Sabrina + Samantha + Sexy + Shorty + Smaller + Sneaky + Stallion + Sultry + Thunder + Vixen + WhinyBot + + + To Preview + + +Record a sample, then click on a voice to hear how it will sound. + + + + + + Subscribe Now + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml index 43fd1f857..f32b74a43 100644 --- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -45,6 +45,10 @@ mouse_opaque="true" name="perm prefs" > + + + + diff --git a/indra/newview/skins/default/xui/es/floater_voice_effect.xml b/indra/newview/skins/default/xui/es/floater_voice_effect.xml new file mode 100644 index 000000000..54b1b5f80 --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_voice_effect.xml @@ -0,0 +1,138 @@ + + + + (Sin transformación de voz) + + + (Activo) + + + (Suscripción cancelada) + + + (¡Nuevo!) + + + Campo + + + Bestia + + + Musculoso + + + Murmullo + + + Camila + + + Aterrador + + + Robot aterrador + + + Cyber + + + Robot profundo + + + Diablo + + + Coqueta + + + Astuto + + + Halloween_2010_Bonus + + + Helio + + + Corpulento + + + Intercom + + + Macho + + + Micro + + + Mini + + + Nano + + + Pesadilla + + + Robot pop + + + Raquel + + + Radio + + + Robot + + + Roxana + + + Sabrina + + + Samanta + + + Sexy + + + Bajito + + + Furtivo + + + Mujeriego + + + Sensual + + + Trueno + + + Tigresa + + + Robot llorica + + + Para probarla + + + Graba una muestra y pulsa en una voz para escuchar cómo suena. + +