Added media ticker to Singularity menu. Will be greyed out for anything not FMOD based. Consider implementing in other sound libraries as a to-do. FMOD Ex also displays an oscillator (making fmod3 do this is too dirty, so that's not going to be backported).

This commit is contained in:
Shyotl
2012-01-03 20:27:56 -06:00
parent dff195d120
commit a3f7399d7d
14 changed files with 437 additions and 5 deletions

View File

@@ -53,7 +53,11 @@ class LLStreamingAudioInterface
virtual void setGain(F32 vol) = 0;
virtual F32 getGain() = 0;
virtual std::string getURL() = 0;
virtual const LLSD *getMetaData() = 0; //return NULL if not supported.
virtual bool supportsMetaData() = 0;
virtual const LLSD *getMetaData() = 0;
virtual bool supportsWaveData() = 0;
virtual bool getWaveData(float* arr, S32 count, S32 stride = 1) = 0;
};
#endif // LL_STREAMINGAUDIO_H

View File

@@ -54,8 +54,11 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
/*virtual*/ void setGain(F32 vol);
/*virtual*/ F32 getGain();
/*virtual*/ std::string getURL();
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not supported.
/*virtual*/ bool supportsMetaData(){return true;}
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
/*virtual*/ bool supportsWaveData(){return false;}
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1){return false};
private:
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
int mFMODInternetStreamChannel;

View File

@@ -334,6 +334,27 @@ void LLStreamingAudio_FMODEX::setGain(F32 vol)
}
}
/*virtual*/ bool LLStreamingAudio_FMODEX::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
{
if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
return false;
static std::vector<float> local_array(count); //Have to have an extra buffer to mix channels. Bleh.
if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
local_array.resize(count);
if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
{
for(S32 i = count;i>=0;i-=stride)
{
arr[i] += local_array[i];
arr[i] *= .5f;
}
return true;
}
return false;
}
///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams

View File

@@ -61,8 +61,11 @@ class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
/*virtual*/ void setGain(F32 vol);
/*virtual*/ F32 getGain();
/*virtual*/ std::string getURL();
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not supported.
/*virtual*/ bool supportsMetaData(){return true;}
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
/*virtual*/ bool supportsWaveData(){return true;}
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
private:
FMOD::System *mSystem;

View File

@@ -537,6 +537,7 @@ set(viewer_SOURCE_FILES
rlvfloaterbehaviour.cpp
rlvviewer2.cpp
shcommandhandler.cpp
shfloatermediaticker.cpp
)
# This gets renamed in the packaging step
@@ -1019,6 +1020,7 @@ set(viewer_HEADER_FILES
rlvfloaterbehaviour.h
rlvviewer2.h
shcommandhandler.h
shfloatermediaticker.h
)
source_group("CMake Rules" FILES ViewerInstall.cmake)

View File

@@ -1,6 +1,35 @@
<?xml version="1.0" ?>
<llsd>
<map>
<key>SHShowMediaTicker</key>
<map>
<key>Comment</key>
<string>Enable media ticker tool for supported audio libraries</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SHMediaTickerRect</key>
<map>
<key>Comment</key>
<string>Rectangle for media ticker</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>200</integer>
<integer>82</integer>
<integer>456</integer>
<integer>50</integer>
</array>
</map>
<key>SHEnableFMODExProfiler</key>
<map>
<key>Comment</key>

View File

@@ -214,6 +214,7 @@
#include "ascentdaycyclemanager.h"
#include "llfloaterblacklist.h"
#include "scriptcounter.h"
#include "shfloatermediaticker.h"
// </edit>
#include "llavatarnamecache.h"
@@ -2053,6 +2054,10 @@ bool idle_startup()
{
LLFloaterAvatarList::createInstance(false);
}
if (gSavedSettings.getBOOL("SHShowMediaTicker"))
{
SHFloaterMediaTicker::showInstance();
}
// </edit>
if (gSavedSettings.getBOOL("ShowCameraControls"))
{
@@ -2073,6 +2078,8 @@ bool idle_startup()
LLFloaterBeacons::showInstance();
}
if (!gNoRender)
{
//Set up cloud rendertypes. Passed argument is unused.

View File

@@ -51,6 +51,7 @@
#include "chatbar_as_cmdline.h"
#if SHY_MOD //Command handler
#include "llvoavatarself.h"
#include "shcommandhandler.h"
#endif //shy_mod
@@ -109,7 +110,6 @@ BOOL LLViewerGesture::trigger(const std::string &trigger_string)
}
}
// private
void LLViewerGesture::doTrigger( BOOL send_chat )
{

View File

@@ -55,7 +55,11 @@ class LLStreamingAudio_MediaPlugins : public LLStreamingAudioInterface
/*virtual*/ void setGain(F32 vol);
/*virtual*/ F32 getGain();
/*virtual*/ std::string getURL();
/*virtual*/ LLSD *getMetaData(){return NULL;} //return NULL if not supported.
/*virtual*/ bool supportsMetaData(){return false;}
/*virtual*/ LLSD *getMetaData(){return NULL;} //return NULL if not playing.
/*virtual*/ virtual bool supportsWaveData(){return false;}
/*virtual*/ virtual bool getWaveData(float* arr, S32 count, S32 stride = 1){return false;}
private:
LLPluginClassMedia* initializeMedia(const std::string& media_type);

View File

@@ -247,6 +247,7 @@
#include "llfloatermessagelog.h"
#include "llfloatervfs.h"
#include "llfloatervfsexplorer.h"
#include "shfloatermediaticker.h"
// </edit>
#include "scriptcounter.h"
@@ -825,6 +826,8 @@ void init_menus()
&handle_sounds_explorer, NULL));
menu->append(new LLMenuItemCallGL( "Asset Blacklist",
&handle_blacklist, NULL));
menu->append(new LLMenuItemCheckGL( "Streaming Audio Display",
&handle_ticker_toggle, &handle_ticker_enabled, &handle_ticker_check, NULL ));

View File

@@ -0,0 +1,262 @@
#include "llviewerprecompiledheaders.h"
#include "shfloatermediaticker.h"
// Library includes
#include "llaudioengine.h"
#include "lliconctrl.h"
#include "llstreamingaudio.h"
#include "lluictrlfactory.h"
// Viewer includes
#include "llviewercontrol.h"
SHFloaterMediaTicker::SHFloaterMediaTicker() : LLFloater()/*, LLSingleton<SHFloaterMediaTicker>()*/,
mPlayState(STATE_PAUSED),
mArtistScrollChars(0),
mTitleScrollChars(0),
mCurScrollChar(0),
mTickerBackground(NULL),
mArtistText(NULL),
mTitleText(NULL),
mVisualizer(NULL)
{
setIsChrome(TRUE);
LLUICtrlFactory::getInstance()->buildFloater(this, "sh_floater_media_ticker.xml");
}
/*virtual*/ BOOL SHFloaterMediaTicker::postBuild()
{
mTickerBackground = getChild<LLIconCtrl>("ticker_background");
mArtistText = getChild<LLTextBox>("artist_text",true,false);
mTitleText = getChild<LLTextBox>("title_text",true,false);
mVisualizer = getChild<LLUICtrl>("visualizer_box",true,false);
mszLoading = getString("loading");
mszPaused = getString("paused");
if(mArtistText) mArtistText->setText(mszPaused);
if(mTitleText) mTitleText->setText(mszPaused);
if(!gAudiop->getStreamingAudioImpl()->supportsWaveData()) //Can't visualize. Extend textboxes.
{
if(mArtistText)
{
LLRect text_rect = mArtistText->getRect();
text_rect.mRight = llmax(mTickerBackground->getRect().mRight-2,text_rect.mRight);
mArtistText->setRect(text_rect);
}
if(mTitleText)
{
LLRect text_rect = mTitleText->getRect();
text_rect.mRight = llmax(mTickerBackground->getRect().mRight-2,text_rect.mRight);
mArtistText->setRect(text_rect);
}
}
return LLFloater::postBuild();
}
/*virtual*/ void SHFloaterMediaTicker::draw()
{
updateTickerText();
LLFloater::draw();
drawOscilloscope();
}
/*virtual*/ void SHFloaterMediaTicker::onOpen()
{
LLFloater::onOpen();
gSavedSettings.setBOOL("SHShowMediaTicker", TRUE);
}
/*virtual*/ void SHFloaterMediaTicker::onClose(bool app_quitting)
{
LLFloater::onClose(app_quitting);
if (!app_quitting)
{
gSavedSettings.setBOOL("SHShowMediaTicker", FALSE);
delete this;
}
}
void SHFloaterMediaTicker::updateTickerText() //called via draw.
{
bool stream_paused = gAudiop->getStreamingAudioImpl()->isPlaying() != 1; //will return 1 if playing.
bool dirty = setPaused(stream_paused);
if(!stream_paused)
{
const LLSD* metadata = gAudiop->getStreamingAudioImpl()->getMetaData();
LLSD artist = metadata ? metadata->get("ARTIST") : LLSD();
LLSD title = metadata ? metadata->get("TITLE") : LLSD();
dirty |= setArtist(artist.isDefined() ? artist.asString() : mszLoading);
dirty |= setTitle(title.isDefined() ? title.asString() : mszLoading);
if(dirty)
resetTicker();
else iterateTickerOffset();
}
}
void SHFloaterMediaTicker::drawOscilloscope() //called via draw.
{
if(!mVisualizer || !gAudiop->getStreamingAudioImpl()->supportsWaveData())
return;
static const S32 NUM_LINE_STRIPS = 64; //How many lines to draw. 64 is more than enough.
static const S32 WAVE_DATA_STEP_SIZE = 4; //Increase to provide more history at expense of cpu/memory.
static const S32 NUM_WAVE_DATA_VALUES = NUM_LINE_STRIPS*WAVE_DATA_STEP_SIZE; //Actual buffer size. Don't toy with this. Change above vars to tweak.
static F32 buf[NUM_WAVE_DATA_VALUES];
if(!gAudiop->getStreamingAudioImpl()->getWaveData(&buf[0],NUM_WAVE_DATA_VALUES,WAVE_DATA_STEP_SIZE))
return;
LLRect root_rect = mVisualizer->getRect();
F32 height = root_rect.getHeight();
F32 height_scale = height / 2.f; //WaveData ranges from 1 to -1, so height_scale = height / 2
F32 width_scale = root_rect.getWidth() / (F32)NUM_WAVE_DATA_VALUES;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4f(0.f,0.f,0.f,.75f);
gGL.pushMatrix();
gGL.translatef((F32)root_rect.mLeft, (F32)root_rect.mBottom + height*.5f, 0.f);
gGL.begin( LLRender::LINE_STRIP );
if((mPlayState != STATE_PAUSED))
{
for(S32 i = NUM_WAVE_DATA_VALUES; i>=0;i-=WAVE_DATA_STEP_SIZE)
gGL.vertex2f((F32)i * width_scale, buf[i]*height_scale);
}
else
{
gGL.vertex2f(0.f, 0.f);
gGL.vertex2f(root_rect.getWidth(), 0.f);
}
gGL.end();
gGL.popMatrix();
gGL.flush();
}
bool SHFloaterMediaTicker::setPaused(bool pause)
{
if(pause == (mPlayState == STATE_PAUSED))
return false;
mPlayState = pause ? STATE_PAUSED : STATE_PLAYING;
if(pause)
{
if(mArtistText) mArtistText->setText(mszPaused);
if(mTitleText) mTitleText->setText(mszPaused);
}
return true;
}
void SHFloaterMediaTicker::resetTicker()
{
mScrollTimer.reset();
mCurScrollChar=0;
if(mArtistText) mArtistText->setText(LLStringExplicit(mszArtist.substr(0,mszArtist.length()-mArtistScrollChars)));
if(mTitleText) mTitleText->setText(LLStringExplicit(mszTitle.substr(0,mszTitle.length()-mTitleScrollChars)));
}
bool SHFloaterMediaTicker::setArtist(const std::string &artist)
{
if(!mArtistText || mszArtist == artist)
return false;
mszArtist = artist;
mArtistText->setText(mszArtist);
mArtistScrollChars = countExtraChars(mArtistText,mszArtist);
return true;
}
bool SHFloaterMediaTicker::setTitle(const std::string &title)
{
if(!mTitleText || mszTitle == title)
return false;
mszTitle=title;
mTitleText->setText(mszTitle);
mTitleScrollChars = countExtraChars(mTitleText,mszTitle);
return true;
}
S32 SHFloaterMediaTicker::countExtraChars(LLTextBox *texbox, const std::string &text)
{
S32 text_width = texbox->getTextPixelWidth();
S32 box_width = texbox->getRect().getWidth();
if(text_width > box_width)
{
const LLFontGL* font = texbox->getFont();
for(S32 count = 1;count<(S32)text.length();count++)
{
//This isn't very efficient...
const std::string substr = text.substr(0,text.length()-count);
if(font->getWidth(substr) <= box_width)
return count;
}
}
return 0;
}
void SHFloaterMediaTicker::iterateTickerOffset()
{
if( (mPlayState != STATE_PAUSED) &&
(mArtistScrollChars || mTitleScrollChars) &&
((!mCurScrollChar && mScrollTimer.getElapsedTimeF32() >= 5.f) ||
( mCurScrollChar && mScrollTimer.getElapsedTimeF32() >= .5f)))
{
if(++mCurScrollChar > llmax(mArtistScrollChars, mTitleScrollChars))
{
if(mScrollTimer.getElapsedTimeF32() >= 2.f) //pause for a bit when it reaches beyond last character.
resetTicker();
}
else
{
mScrollTimer.reset();
if(mArtistText && mCurScrollChar <= mArtistScrollChars)
{
mArtistText->setText(LLStringExplicit(mszArtist.substr(mCurScrollChar,mszArtist.length()-mArtistScrollChars+mCurScrollChar)));
}
if(mTitleText && mCurScrollChar <= mTitleScrollChars)
{
mTitleText->setText(LLStringExplicit(mszTitle.substr(mCurScrollChar,mszTitle.length()-mTitleScrollChars+mCurScrollChar)));
}
}
}
}
/*static*/
void SHFloaterMediaTicker::showInstance()
{
if(!handle_ticker_enabled(NULL))
return;
if(!SHFloaterMediaTicker::instanceExists())
{
SHFloaterMediaTicker::getInstance();
}
}
BOOL handle_ticker_enabled(void *)
{
return gAudiop && gAudiop->getStreamingAudioImpl() && gAudiop->getStreamingAudioImpl()->supportsMetaData();
}
BOOL handle_ticker_check(void *)
{
return SHFloaterMediaTicker::instanceExists();
}
void handle_ticker_toggle(void *)
{
if(!handle_ticker_enabled(NULL))
return;
if(!SHFloaterMediaTicker::instanceExists())
{
SHFloaterMediaTicker::getInstance();
}
else
{
SHFloaterMediaTicker::getInstance()->close();
}
}

View File

@@ -0,0 +1,55 @@
#include "llfloater.h"
class LLIconCtrl;
class SHFloaterMediaTicker : public LLFloater, public LLSingleton<SHFloaterMediaTicker>
{
friend class LLSingleton<SHFloaterMediaTicker>;
public:
SHFloaterMediaTicker(); //ctor
virtual ~SHFloaterMediaTicker() {}
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
/*virtual*/ void onOpen();
/*virtual*/ void onClose(bool app_quitting);
static void showInstance(); //use to create.
private:
void updateTickerText(); //called via draw.
void drawOscilloscope(); //called via draw.
bool setPaused(bool pause); //returns true on state change.
void resetTicker(); //Resets tickers to their innitial values (no offset).
bool setArtist(const std::string &artist); //returns true on change
bool setTitle(const std::string &title); //returns true on change
S32 countExtraChars(LLTextBox *texbox, const std::string &text); //calculates how many characters are truncated by bounds.
void iterateTickerOffset(); //Logic that actually shuffles the text to the left.
enum ePlayState
{
STATE_PAUSED,
STATE_PLAYING
};
ePlayState mPlayState;
std::string mszLoading;
std::string mszPaused;
std::string mszArtist;
std::string mszTitle;
LLTimer mScrollTimer;
S32 mArtistScrollChars;
S32 mTitleScrollChars;
S32 mCurScrollChar;
//UI elements
LLIconCtrl* mTickerBackground;
LLTextBox* mArtistText;
LLTextBox* mTitleText;
LLUICtrl* mVisualizer;
};
//Menu callbacks.
BOOL handle_ticker_enabled(void *);
BOOL handle_ticker_check(void *);
void handle_ticker_toggle(void *);

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater can_close="true" can_drag_on_left="false" can_minimize="false" can_resize="false"
height="32" min_height="32" min_width="256" name="mediaticker" rect_control="SHMediaTickerRect" control_name="SHShowMediaTicker"
title="" width="256">
<icon bottom="-30" color="1, 1, 1, 1" follows="top|right" height="28"
image_name="ticker_background_small.tga" left="2" mouse_opaque="false" name="ticker_background"
width="234" />
<text text_color="0,0,0,1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-18" drop_shadow_visible="true" follows="top|right"
font="SansSerifBold" h_pad="0" halign="left" height="16" left="4"
mouse_opaque="true" name="artist_label" v_pad="0" width="50">
Artist:
</text>
<text text_color="0,0,0,1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-18" drop_shadow_visible="true" follows="top|right"
font="SansSerifBold" h_pad="0" halign="left" height="16" left="50"
mouse_opaque="true" name="artist_text" v_pad="0" width="125">
</text>
<text text_color="0,0,0,1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-32" drop_shadow_visible="true" follows="top|right"
font="SansSerifBold" h_pad="0" halign="left" height="16" left="4"
mouse_opaque="true" name="title_label" v_pad="0" width="50">
Title:
</text>
<text text_color="0,0,0,1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-32" drop_shadow_visible="true" follows="top|right"
font="SansSerifBold" h_pad="0" halign="left" height="16" left="50"
mouse_opaque="true" name="title_text" v_pad="0" width="125">
</text>
<locate bottom="-28" height="24" left="177" name="visualizer_box" width="58"/>
<string name="paused">
(not playing)
</string>
<string name="loading">
(loading...)
</string>
</floater>