EXT-7337 WIP Voice morph previewing

Separate Play and Stop callbacks, to allow single click previews in the effect list.
meow-7.2.2
Aimee Linden 2010-05-23 02:22:48 +01:00
parent 32826f31eb
commit 1ebbe19691
6 changed files with 142 additions and 59 deletions

View File

@ -43,6 +43,7 @@ LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& 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.Add", boost::bind(&LLFloaterVoiceEffect::onClickAdd, this));
mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
}
@ -68,6 +69,7 @@ BOOL LLFloaterVoiceEffect::postBuild()
mVoiceEffectList = getChild<LLScrollListCtrl>("voice_effect_list");
if (mVoiceEffectList)
{
mVoiceEffectList->setCommitCallback(boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
mVoiceEffectList->setDoubleClickCallback(boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
}
@ -80,7 +82,8 @@ BOOL LLFloaterVoiceEffect::postBuild()
effect_interface->enablePreviewBuffer(true);
}
update();
refreshEffectList();
updateControls();
return TRUE;
}
@ -95,7 +98,7 @@ void LLFloaterVoiceEffect::onClose(bool app_quitting)
}
}
void LLFloaterVoiceEffect::update()
void LLFloaterVoiceEffect::refreshEffectList()
{
if (!mVoiceEffectList)
{
@ -194,23 +197,42 @@ void LLFloaterVoiceEffect::update()
mVoiceEffectList->setValue(effect_interface->getVoiceEffect());
mVoiceEffectList->setEnabled(true);
}
void LLFloaterVoiceEffect::updateControls()
{
bool recording = false;
bool playing = false;
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
if (effect_interface)
{
recording = effect_interface->isPreviewRecording();
playing = effect_interface->isPreviewPlaying();
}
// Update button states
// *TODO: Should separate this from rebuilding the effects list, to avoid rebuilding it unnecessarily
bool recording = effect_interface->isPreviewRecording();
getChild<LLButton>("record_btn")->setVisible(!recording);
getChild<LLButton>("record_stop_btn")->setVisible(recording);
getChild<LLButton>("play_btn")->setEnabled(effect_interface->isPreviewReady());
bool playing = effect_interface->isPreviewPlaying();
getChild<LLButton>("play_btn")->setVisible(!playing);
getChild<LLButton>("play_stop_btn")->setVisible(playing);
getChild<LLButton>("play_btn")->setEnabled(effect_interface->isPreviewReady());
if (!mVoiceEffectList)
{
mVoiceEffectList->setValue(effect_interface->getVoiceEffect());
}
}
// virtual
void LLFloaterVoiceEffect::onVoiceEffectChanged(bool new_effects)
{
update();
if (new_effects)
{
refreshEffectList();
}
updateControls();
}
void LLFloaterVoiceEffect::onClickRecord()
@ -219,11 +241,9 @@ void LLFloaterVoiceEffect::onClickRecord()
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
if (effect_interface)
{
bool record = !effect_interface->isPreviewRecording();
effect_interface->recordPreviewBuffer(record);
getChild<LLButton>("record_btn")->setVisible(!record);
getChild<LLButton>("record_stop_btn")->setVisible(record);
effect_interface->recordPreviewBuffer();
}
updateControls();
}
void LLFloaterVoiceEffect::onClickPlay()
@ -239,11 +259,20 @@ void LLFloaterVoiceEffect::onClickPlay()
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
if (effect_interface)
{
bool play = !effect_interface->isPreviewPlaying();
effect_interface->playPreviewBuffer(play, effect_id);
getChild<LLButton>("play_btn")->setVisible(!play);
getChild<LLButton>("play_stop_btn")->setVisible(play);
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::onClickAdd()

View File

@ -53,13 +53,15 @@ public:
virtual void onClose(bool app_quitting);
private:
void update();
void refreshEffectList();
void updateControls();
/// Called by voice effect provider when voice effect list is changed.
virtual void onVoiceEffectChanged(bool new_effects);
void onClickRecord();
void onClickPlay();
void onClickStop();
void onClickAdd();
void onClickActivate();

View File

@ -307,8 +307,9 @@ public:
/// @name Preview buffer
//@{
virtual void enablePreviewBuffer(bool enable) = 0;
virtual void recordPreviewBuffer(bool record) = 0;
virtual void playPreviewBuffer(bool play, const LLUUID& effect_id = LLUUID::null) = 0;
virtual void recordPreviewBuffer() = 0;
virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) = 0;
virtual void stopPreviewBuffer() = 0;
virtual bool isPreviewRecording() = 0;
virtual bool isPreviewReady() = 0;

View File

@ -348,7 +348,8 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
mCaptureBufferMode(false),
mCaptureBufferRecording(false),
mCaptureBufferRecorded(false),
mCaptureBufferPlaying(false)
mCaptureBufferPlaying(false),
mPlayRequestCount(0)
{
mSpeakerVolume = scale_speaker_volume(0);
@ -1137,28 +1138,39 @@ void LLVivoxVoiceClient::stateMachine()
case stateCaptureBufferPaused:
if (!mCaptureBufferMode)
{
// Leaving capture mode.
mCaptureBufferRecording = false;
mCaptureBufferRecorded = false;
mCaptureBufferPlaying = false;
// Return to stateNoChannel to trigger reconnection to a channel.
setState(stateNoChannel);
}
else if (mCaptureBufferRecording)
{
setState(stateCaptureBufferRecStart);
// Update UI, should really be separated from the VoiceFont callback
notifyVoiceFontObservers();
}
else if (mCaptureBufferPlaying)
{
setState(stateCaptureBufferPlayStart);
notifyVoiceFontObservers();
}
break;
//MARK: stateCaptureBufferRecStart
case stateCaptureBufferRecStart:
captureBufferRecordStartSendMessage();
// Flag that something is recorded to allow playback.
mCaptureBufferRecorded = true;
// Start the timer, recording will be stopped when it expires.
mCaptureTimer.start();
mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME);
// Update UI, should really use a separate callback.
notifyVoiceFontObservers(false);
setState(stateCaptureBufferRecording);
break;
@ -1167,27 +1179,47 @@ void LLVivoxVoiceClient::stateMachine()
if (!mCaptureBufferMode || !mCaptureBufferRecording ||
mCaptureBufferPlaying || mCaptureTimer.hasExpired())
{
mCaptureBufferRecording = false;
// Stop recording
captureBufferRecordStopSendMessage();
mCaptureBufferRecording = false;
// Update UI, should really use a separate callback.
notifyVoiceFontObservers(false);
setState(stateCaptureBufferPaused);
notifyVoiceFontObservers();
}
break;
//MARK: stateCaptureBufferPlayStart
case stateCaptureBufferPlayStart:
captureBufferPlayStartSendMessage(mPreviewVoiceFontID);
captureBufferPlayStartSendMessage(mPreviewVoiceFont);
// Store the voice font being previewed, so that we know to restart if it changes.
mPreviewVoiceFontLast = mPreviewVoiceFont;
// Update UI, should really use a separate callback.
notifyVoiceFontObservers(false);
setState(stateCaptureBufferPlaying);
break;
//MARK: stateCaptureBufferPlaying
case stateCaptureBufferPlaying:
if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording)
if (mCaptureBufferPlaying && mPreviewVoiceFont != mPreviewVoiceFontLast)
{
mCaptureBufferPlaying = false;
// If the preview voice font changes, restart playing with the new font.
setState(stateCaptureBufferPlayStart);
}
else if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording)
{
// Stop playing.
captureBufferPlayStopSendMessage();
mCaptureBufferPlaying = false;
// Update UI, should really use a separate callback.
notifyVoiceFontObservers(false);
setState(stateCaptureBufferPaused);
notifyVoiceFontObservers();
}
break;
@ -1723,7 +1755,7 @@ void LLVivoxVoiceClient::stateMachine()
{
mAudioSessionChanged = false;
notifyParticipantObservers();
notifyVoiceFontObservers();
notifyVoiceFontObservers(false);
}
else if (mAudioSession && mAudioSession->mParticipantsChanged)
{
@ -3546,7 +3578,11 @@ void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, s
}
else if (mediaCompletionType == "AuxBufferAudioRender")
{
mCaptureBufferPlaying = false;
// Ignore all but the last stop event
if (--mPlayRequestCount <= 0)
{
mCaptureBufferPlaying = false;
}
}
else
{
@ -6392,7 +6428,7 @@ bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id)
gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString());
sessionSetVoiceFontSendMessage(mAudioSession);
notifyVoiceFontObservers();
notifyVoiceFontObservers(false);
return true;
}
@ -6669,14 +6705,13 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st
}
mVoiceFontsReceived = true;
notifyVoiceFontObservers(mVoiceFontsNew);
mVoiceFontsNew = false;
notifyVoiceFontObservers(true);
}
void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString)
{
// Voice font list entries were updated via addVoiceFont() during parsing.
notifyVoiceFontObservers();
notifyVoiceFontObservers(true);
}
void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer)
{
@ -6711,49 +6746,58 @@ void LLVivoxVoiceClient::enablePreviewBuffer(bool enable)
}
}
void LLVivoxVoiceClient::recordPreviewBuffer(bool record)
void LLVivoxVoiceClient::recordPreviewBuffer()
{
if (record && !mCaptureBufferMode)
if (!mCaptureBufferMode)
{
LL_DEBUGS("Voice") << "Cannot start recording, not in preview mode." << LL_ENDL;
LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL;
mCaptureBufferRecording = false;
return;
}
mCaptureBufferRecording = record;
mCaptureBufferRecording = true;
}
void LLVivoxVoiceClient::playPreviewBuffer(bool play, const LLUUID& effect_id)
void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id)
{
if (play)
if (!mCaptureBufferMode)
{
if (mCaptureBufferMode && mCaptureBufferRecorded)
{
mPreviewVoiceFontID = effect_id;
}
else
{
LL_DEBUGS("Voice") << "No preview buffer to play." << LL_ENDL;
return;
}
LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL;
mCaptureBufferRecording = false;
return;
}
mCaptureBufferPlaying = play;
if (!mCaptureBufferRecorded)
{
// Can't play until we have something recorded!
mCaptureBufferPlaying = false;
return;
}
mPreviewVoiceFont = effect_id;
mCaptureBufferPlaying = true;
}
void LLVivoxVoiceClient::stopPreviewBuffer()
{
mCaptureBufferRecording = false;
mCaptureBufferPlaying = false;
}
bool LLVivoxVoiceClient::isPreviewRecording()
{
return mCaptureBufferRecording;
return (mCaptureBufferMode && mCaptureBufferRecording);
}
bool LLVivoxVoiceClient::isPreviewReady()
{
return mCaptureBufferRecorded;
return (mCaptureBufferMode && mCaptureBufferRecorded);
}
bool LLVivoxVoiceClient::isPreviewPlaying()
{
return mCaptureBufferPlaying;
return (mCaptureBufferMode && mCaptureBufferPlaying);
}
void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
@ -6811,6 +6855,10 @@ void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_f
{
if(!mAccountHandle.empty())
{
// Track how may play requests are sent, so we know how many stop events to
// expect before play actually stops.
++mPlayRequestCount;
std::ostringstream stream;
LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL;

View File

@ -258,8 +258,9 @@ public:
/// @name Effect preview buffer
//@{
virtual void enablePreviewBuffer(bool enable);
virtual void recordPreviewBuffer(bool record);
virtual void playPreviewBuffer(bool play, const LLUUID& effect_id = LLUUID::null);
virtual void recordPreviewBuffer();
virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null);
virtual void stopPreviewBuffer();
virtual bool isPreviewRecording();
virtual bool isPreviewReady();
@ -925,7 +926,9 @@ private:
bool mCaptureBufferPlaying; // A voice sample is being played.
LLTimer mCaptureTimer;
LLUUID mPreviewVoiceFontID;
LLUUID mPreviewVoiceFont;
LLUUID mPreviewVoiceFontLast;
S32 mPlayRequestCount;
};
/**

View File

@ -153,7 +153,7 @@
top_delta="0"
width="135">
<button.commit_callback
function="VoiceEffect.Record" />
function="VoiceEffect.Stop" />
</button>
<button
follows="left|bottom"
@ -177,6 +177,6 @@
top_delta="0"
width="135">
<button.commit_callback
function="VoiceEffect.Play" />
function="VoiceEffect.Stop" />
</button>
</floater>