Attempt #2 at taming the meter toolbars

It corrects several "multiple project" problems with the
meter toolbars and meters.

In addition, there was a "multiple project" issue where
the transport buttons didn't disable properly in the
non-active project.
This commit is contained in:
lllucius 2014-12-19 16:38:56 +00:00
parent 5d526a8009
commit 9bbc261321
11 changed files with 162 additions and 88 deletions

View File

@ -1131,6 +1131,7 @@ void AudioIO::StartMonitoring(double sampleRate)
(void)success;
wxCommandEvent e(EVT_AUDIOIO_MONITOR);
e.SetEventObject(mOwningProject);
e.SetInt(true);
wxTheApp->ProcessEvent(e);
@ -1191,8 +1192,6 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
mTimeTrack = timeTrack;
mListener = listener;
mInputMeter = NULL;
mOutputMeter = NULL;
mRate = sampleRate;
mT0 = t0;
mT1 = t1;
@ -1441,6 +1440,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
if (mNumPlaybackChannels > 0)
{
wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
e.SetEventObject(mOwningProject);
e.SetInt(true);
wxTheApp->ProcessEvent(e);
}
@ -1448,6 +1448,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
if (mNumCaptureChannels > 0)
{
wxCommandEvent e(EVT_AUDIOIO_CAPTURE);
e.SetEventObject(mOwningProject);
e.SetInt(true);
wxTheApp->ProcessEvent(e);
}
@ -1620,9 +1621,9 @@ bool AudioIO::StartPortMidiStream()
}
#endif
void AudioIO::SetCaptureMeter(Meter *meter)
void AudioIO::SetCaptureMeter(AudacityProject *project, Meter *meter)
{
if (!mOwningProject || mOwningProject == GetActiveProject())
if (!mOwningProject || mOwningProject == project)
{
mInputMeter = meter;
if (mInputMeter)
@ -1632,9 +1633,9 @@ void AudioIO::SetCaptureMeter(Meter *meter)
}
}
void AudioIO::SetPlaybackMeter(Meter *meter)
void AudioIO::SetPlaybackMeter(AudacityProject *project, Meter *meter)
{
if (!mOwningProject || mOwningProject == GetActiveProject())
if (!mOwningProject || mOwningProject == project)
{
mOutputMeter = meter;
if (mOutputMeter)
@ -1742,6 +1743,7 @@ void AudioIO::StopStream()
if (mNumPlaybackChannels > 0)
{
wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
e.SetEventObject(mOwningProject);
e.SetInt(false);
wxTheApp->ProcessEvent(e);
}
@ -1749,6 +1751,7 @@ void AudioIO::StopStream()
if (mNumCaptureChannels > 0)
{
wxCommandEvent e(mStreamToken == 0 ? EVT_AUDIOIO_MONITOR : EVT_AUDIOIO_CAPTURE);
e.SetEventObject(mOwningProject);
e.SetInt(false);
wxTheApp->ProcessEvent(e);
}
@ -1920,6 +1923,9 @@ void AudioIO::StopStream()
// Only set token to 0 after we're totally finished with everything
//
mStreamToken = 0;
mNumCaptureChannels = 0;
mNumPlaybackChannels = 0;
}
void AudioIO::SetPaused(bool state)

View File

@ -323,8 +323,8 @@ class AUDACITY_DLL_API AudioIO {
double AILAGetLastDecisionTime();
#endif
void SetCaptureMeter(Meter *meter);
void SetPlaybackMeter(Meter *meter);
void SetCaptureMeter(AudacityProject *project, Meter *meter);
void SetPlaybackMeter(AudacityProject *project, Meter *meter);
private:
/** \brief Set the current VU meters - this should be done once after

View File

@ -1150,7 +1150,10 @@ void AudacityProject::CreateMenusAndCommands()
c->AddSeparator();
c->AddItem(wxT("DeviceInfo"), _("Au&dio Device Info..."), FN(OnAudioDeviceInfo));
c->AddItem(wxT("DeviceInfo"), _("Au&dio Device Info..."), FN(OnAudioDeviceInfo),
AudioIONotBusyFlag,
AudioIONotBusyFlag);
c->AddItem(wxT("Log"), _("Show &Log..."), FN(OnShowLog));
c->AddSeparator();

View File

@ -308,7 +308,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
if (mLeftTrack) {
#endif
mMeter =
new Meter(this, -1, // wxWindow* parent, wxWindowID id,
new Meter(GetActiveProject(), // AudacityProject* project,
this, -1, // wxWindow* parent, wxWindowID id,
false, // bool isInput
ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
Meter::MixerTrackCluster); // Style style = HorizontalStereo,

View File

@ -4196,7 +4196,7 @@ void AudacityProject::SetPlaybackMeter(Meter *playback)
mPlaybackMeter = playback;
if (gAudioIO)
{
gAudioIO->SetPlaybackMeter(mPlaybackMeter);
gAudioIO->SetPlaybackMeter(this, mPlaybackMeter);
}
}
@ -4208,9 +4208,10 @@ Meter *AudacityProject::GetCaptureMeter()
void AudacityProject::SetCaptureMeter(Meter *capture)
{
mCaptureMeter = capture;
if (gAudioIO)
{
gAudioIO->SetCaptureMeter(mCaptureMeter);
gAudioIO->SetCaptureMeter(this, mCaptureMeter);
}
}

View File

@ -2106,9 +2106,14 @@ EffectUIHost::EffectUIHost(wxWindow *parent,
mEffect = effect;
mClient = client;
mProject = GetActiveProject();
mInitialized = false;
mDisableTransport = false;
mEnable = false;
mPlayPos = 0.0;
mClient->SetUIHost(this);
@ -2341,9 +2346,7 @@ void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt))
void EffectUIHost::OnApply(wxCommandEvent & WXUNUSED(evt))
{
AudacityProject *p = GetActiveProject();
if (p->mViewInfo.selectedRegion.isPoint())
if (mProject->mViewInfo.selectedRegion.isPoint())
{
wxMessageBox(_("You must select audio in the project window."));
return;
@ -2531,26 +2534,24 @@ void EffectUIHost::OnEnable(wxCommandEvent & WXUNUSED(evt))
void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
{
AudacityProject *p = GetActiveProject();
if (mPlaying)
{
mPlayPos = gAudioIO->GetStreamTime();
p->GetControlToolBar()->StopPlaying();
mProject->GetControlToolBar()->StopPlaying();
}
else
{
if (p->IsPlayRegionLocked())
if (mProject->IsPlayRegionLocked())
{
double t0, t1;
p->GetPlayRegion(&t0, &t1);
mProject->GetPlayRegion(&t0, &t1);
mRegion.setTimes(t0, t1);
mPlayPos = mRegion.t0();
}
else if (p->mViewInfo.selectedRegion.t0() != mRegion.t0() ||
p->mViewInfo.selectedRegion.t1() != mRegion.t1())
else if (mProject->mViewInfo.selectedRegion.t0() != mRegion.t0() ||
mProject->mViewInfo.selectedRegion.t1() != mRegion.t1())
{
mRegion = p->mViewInfo.selectedRegion;
mRegion = mProject->mViewInfo.selectedRegion;
mPlayPos = mRegion.t0();
}
@ -2559,7 +2560,7 @@ void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
mPlayPos = mRegion.t1();
}
p->GetControlToolBar()->PlayPlayRegion(mPlayPos, mRegion.t1());
mProject->GetControlToolBar()->PlayPlayRegion(mPlayPos, mRegion.t1());
}
}
@ -2610,11 +2611,26 @@ void EffectUIHost::OnPlayback(wxCommandEvent & evt)
{
evt.Skip();
mPlaying = evt.GetInt() != 0;
if (evt.GetInt() != 0)
{
if (evt.GetEventObject() != mProject)
{
mDisableTransport = true;
}
else
{
mPlaying = true;
}
}
else
{
mDisableTransport = false;
mPlaying = false;
}
if (mPlaying)
{
mRegion = GetActiveProject()->mViewInfo.selectedRegion;
mRegion = mProject->mViewInfo.selectedRegion;
mPlayPos = mRegion.t0();
}
@ -2625,8 +2641,23 @@ void EffectUIHost::OnCapture(wxCommandEvent & evt)
{
evt.Skip();
mCapturing = evt.GetInt() != 0;
mCloseBtn->SetFocus();
if (evt.GetInt() != 0)
{
if (evt.GetEventObject() != mProject)
{
mDisableTransport = true;
}
else
{
mCapturing = true;
}
}
else
{
mDisableTransport = false;
mCapturing = false;
}
UpdateControls();
}
@ -2781,9 +2812,21 @@ wxBitmap EffectUIHost::CreateBitmap(const char *xpm[], bool up, bool pusher)
void EffectUIHost::UpdateControls()
{
if (mCapturing || mDisableTransport)
{
// Don't allow focus to get trapped
wxWindow *focus = FindFocus();
if (focus == mRewindBtn || focus == mFFwdBtn || focus == mPlayBtn || focus == mEnableBtn)
{
mCloseBtn->SetFocus();
}
}
mApplyBtn->Enable(!mCapturing);
mRewindBtn->Enable(!mCapturing);
mFFwdBtn->Enable(!mCapturing);
mRewindBtn->Enable(!(mCapturing || mDisableTransport));
mFFwdBtn->Enable(!(mCapturing || mDisableTransport));
(!mIsGUI ? mPlayToggleBtn : mPlayBtn)->Enable(!(mCapturing || mDisableTransport));
(!mIsGUI ? mEnableToggleBtn : mEnableBtn)->Enable(!(mCapturing || mDisableTransport));
wxBitmapButton *bb;
@ -2794,8 +2837,6 @@ void EffectUIHost::UpdateControls()
/* i18n-hint: The access key "&P" should be the same in
"Stop &Playback" and "Start &Playback" */
mPlayToggleBtn->SetLabel(_("Stop &Playback"));
//mPlayToggleBtn->SetValue(true);
mPlayToggleBtn->Enable(!mCapturing);
mPlayToggleBtn->Refresh();
}
else
@ -2803,7 +2844,6 @@ void EffectUIHost::UpdateControls()
bb = (wxBitmapButton *) mPlayBtn;
bb->SetBitmapLabel(mStopBM);
bb->SetBitmapDisabled(mStopDisabledBM);
mPlayBtn->Enable(!mCapturing);
#if defined(__WXMAC__)
mPlayBtn->SetName(_("Stop &Playback"));
#else
@ -2818,8 +2858,6 @@ void EffectUIHost::UpdateControls()
/* i18n-hint: The access key "&P" should be the same in
"Stop &Playback" and "Start &Playback" */
mPlayToggleBtn->SetLabel(_("Start &Playback"));
//mPlayToggleBtn->SetValue(false);
mPlayToggleBtn->Enable(!mCapturing);
mPlayToggleBtn->Refresh();
}
else
@ -2827,7 +2865,6 @@ void EffectUIHost::UpdateControls()
bb = (wxBitmapButton *) mPlayBtn;
bb->SetBitmapLabel(mPlayBM);
bb->SetBitmapDisabled(mPlayDisabledBM);
mPlayBtn->Enable(!mCapturing);
#if defined(__WXMAC__)
mPlayBtn->SetName(_("Start &Playback"));
#else
@ -2843,8 +2880,6 @@ void EffectUIHost::UpdateControls()
/* i18n-hint: The access key "&O" should be the same in
"Enable &Effect" and "Disable &Effect" */
mEnableToggleBtn->SetLabel(_("Enable &Effect"));
//mEnableToggleBtn->SetValue(true);
mEnableToggleBtn->Enable(!mCapturing);
mEnableToggleBtn->Refresh();
}
else
@ -2852,7 +2887,6 @@ void EffectUIHost::UpdateControls()
bb = (wxBitmapButton *) mEnableBtn;
bb->SetBitmapLabel(mEnableBM);
bb->SetBitmapDisabled(mEnableDisabledBM);
mEnableBtn->Enable(!mCapturing);
#if defined(__WXMAC__)
mEnableBtn->SetName(_("Enable &Effect"));
#else
@ -2867,8 +2901,6 @@ void EffectUIHost::UpdateControls()
/* i18n-hint: The access key "&O" should be the same in
"Enable &Effect" and "Disable &Effect" */
mEnableToggleBtn->SetLabel(_("Disable &Effect"));
//mEnableToggleBtn->SetValue(false);
mEnableToggleBtn->Enable(!mCapturing);
mEnableToggleBtn->Refresh();
}
else
@ -2876,7 +2908,6 @@ void EffectUIHost::UpdateControls()
bb = (wxBitmapButton *) mEnableBtn;
bb->SetBitmapLabel(mDisableBM);
bb->SetBitmapDisabled(mDisableDisabledBM);
mEnableBtn->Enable(!mCapturing);
#if defined(__WXMAC__)
mEnableBtn->SetName(_("Disable &Effect"));
#else

View File

@ -28,6 +28,7 @@ class wxWindow;
#include "../Experimental.h"
#include "../WaveTrack.h"
#include "../Project.h"
#include "../SelectedRegion.h"
#include "../Shuttle.h"
#include "../ShuttleGui.h"
@ -523,6 +524,7 @@ private:
void LoadUserPresets();
private:
AudacityProject *mProject;
wxWindow *mParent;
Effect *mEffect;
EffectUIClientInterface *mClient;
@ -554,6 +556,7 @@ private:
wxBitmap mDisableBM;
wxBitmap mDisableDisabledBM;
bool mDisableTransport;
bool mPlaying;
bool mCapturing;

View File

@ -90,7 +90,8 @@ void MeterToolBar::Populate()
if( mWhichMeters & kWithRecordMeter ){
//JKC: Record on left, playback on right. Left to right flow
//(maybe we should do it differently for Arabic language :-) )
mRecordMeter = new Meter( this,
mRecordMeter = new Meter( mProject,
this,
wxID_ANY,
true,
wxDefaultPosition,
@ -105,7 +106,8 @@ void MeterToolBar::Populate()
}
if( mWhichMeters & kWithPlayMeter ){
mPlayMeter = new Meter( this,
mPlayMeter = new Meter( mProject,
this,
wxID_ANY,
false,
wxDefaultPosition,

View File

@ -66,8 +66,8 @@ enum
TransportBarID,
ToolsBarID,
MeterBarID,
PlayMeterBarID, // RecorderMeterBarID should be after PlayMeterBarID
RecordMeterBarID, // to ensure proper meter style setup during initialization
RecordMeterBarID,
PlayMeterBarID,
MixerBarID,
EditBarID,
TranscriptionBarID,

View File

@ -187,7 +187,6 @@ enum {
};
BEGIN_EVENT_TABLE(Meter, wxPanel)
EVT_COMMAND(wxID_ANY, EVT_AUDIOIO_MONITOR, Meter::OnAudioIOMonitor)
EVT_TIMER(OnMeterUpdateID, Meter::OnMeterUpdate)
EVT_MOUSE_EVENTS(Meter::OnMouse)
EVT_ERASE_BACKGROUND(Meter::OnErase)
@ -212,13 +211,15 @@ END_EVENT_TABLE()
IMPLEMENT_CLASS(Meter, wxPanel)
Meter::Meter(wxWindow* parent, wxWindowID id,
Meter::Meter(AudacityProject *project,
wxWindow* parent, wxWindowID id,
bool isInput,
const wxPoint& pos /*= wxDefaultPosition*/,
const wxSize& size /*= wxDefaultSize*/,
Style style /*= HorizontalStereo*/,
float fDecayRate /*= 60.0f*/)
: wxPanel(parent, id, pos, size),
mProject(project),
mQueue(1024),
mWidth(size.x), mHeight(size.y),
mIsInput(isInput),
@ -234,6 +235,7 @@ Meter::Meter(wxWindow* parent, wxWindowID id,
mT(0),
mRate(0),
mMonitoring(false),
mActive(false),
mNumBars(0),
mLayoutValid(false),
mBitmap(NULL),
@ -254,8 +256,16 @@ Meter::Meter(wxWindow* parent, wxWindowID id,
mRightSize = wxSize(0, 0);
if (mIsInput) {
if (mStyle != MixerTrackCluster)
mMeterDisabled = 1L;// Monitoring off by default.
// Register for AudioIO Monitor events
wxTheApp->Connect(EVT_AUDIOIO_MONITOR,
wxCommandEventHandler(Meter::OnAudioIOStatus),
NULL,
this);
wxTheApp->Connect(EVT_AUDIOIO_CAPTURE,
wxCommandEventHandler(Meter::OnAudioIOStatus),
NULL,
this);
mPen = wxPen( theTheme.Colour( clrMeterInputPen ), 1, wxSOLID);
mBrush = wxBrush( theTheme.Colour( clrMeterInputBrush ), wxSOLID);
mRMSBrush = wxBrush( theTheme.Colour( clrMeterInputRMSBrush ), wxSOLID);
@ -293,13 +303,6 @@ Meter::Meter(wxWindow* parent, wxWindowID id,
mBar[i].clipping = false;
mBar[i].isclipping = false;
}
// Register for AudioIO Monitor events
wxTheApp->Connect(EVT_AUDIOIO_MONITOR,
wxCommandEventHandler(Meter::OnAudioIOMonitor),
NULL,
this);
}
void Meter::Clear()
@ -328,11 +331,18 @@ void Meter::CreateIcon(int WXUNUSED(aquaOffset))
Meter::~Meter()
{
// Register for AudioIO Monitor events
wxTheApp->Disconnect(EVT_AUDIOIO_MONITOR,
wxCommandEventHandler(Meter::OnAudioIOMonitor),
NULL,
this);
if (mIsInput)
{
// Unregister for AudioIO Monitor events
wxTheApp->Disconnect(EVT_AUDIOIO_MONITOR,
wxCommandEventHandler(Meter::OnAudioIOStatus),
NULL,
this);
wxTheApp->Disconnect(EVT_AUDIOIO_CAPTURE,
wxCommandEventHandler(Meter::OnAudioIOStatus),
NULL,
this);
}
// LLL: This prevents a crash during termination if monitoring
// is active.
@ -365,8 +375,8 @@ void Meter::UpdatePrefs()
if (mIsInput)
{
// Default is disabled i.e. monitoring off when we start.
mMeterDisabled = gPrefs->Read(wxT("/Meter/MeterInputDisabled"), (long)1);
// Default is disabled i.e. metering off when we start.
mMeterDisabled = gPrefs->Read(wxT("/Meter/MeterInputDisabled"), (long)0);
}
else
{
@ -649,6 +659,13 @@ void Meter::OnMeterUpdate(wxTimerEvent & WXUNUSED(event))
double maxPeak = 0.0;
bool discarded = false;
#endif
// We shouldn't receive any events if the meter is disabled, but clear it to be safe
if (mMeterDisabled) {
mQueue.Clear();
return;
}
// There may have been several update messages since the last
// time we got to this function. Catch up to real-time by
// popping them off until there are none left. It is necessary
@ -659,12 +676,6 @@ void Meter::OnMeterUpdate(wxTimerEvent & WXUNUSED(event))
double deltaT = msg.numFrames / mRate;
int j;
// <Why is this in the loop, rather than top of the method?
// Or just a condition on the following, so we pop all the msgs while disabled?>
if (mMeterDisabled)
return;
//wxLogDebug(wxT("Pop: %s"), msg.toString().c_str());
mT += deltaT;
for(j=0; j<mNumBars; j++) {
mBar[j].isclipping = false;
@ -1208,7 +1219,7 @@ void Meter::HandlePaint(wxDC &destDC)
// And for the case of horizontal meter we tell the user they can click to monitor.
// It's a nice extra, not an essential, as they have a start monitoring menu item.
if( mMeterDisabled && !mBar[0].vert)
if( mIsInput && !mActive && !mBar[0].vert)
{
destDC.SetBrush( mBkgndBrush );
destDC.SetPen( *wxTRANSPARENT_PEN );
@ -1229,7 +1240,6 @@ void Meter::HandlePaint(wxDC &destDC)
destDC.SetBackgroundMode( wxTRANSPARENT );
destDC.DrawText( Text, TextPos );
}
}
void Meter::RepaintBarsNow()
@ -1444,18 +1454,9 @@ void Meter::StartMonitoring()
if (gAudioIO->IsMonitoring()){
gAudioIO->StopStream();
if (!mMeterDisabled){
wxCommandEvent dummy;
OnDisableMeter(dummy);
}
}
if (start && !gAudioIO->IsBusy()){
if (mMeterDisabled){
wxCommandEvent dummy;
OnDisableMeter(dummy);
}
AudacityProject *p = GetActiveProject();
if (p){
gAudioIO->StartMonitoring(p->GetRate());
@ -1469,16 +1470,37 @@ void Meter::StartMonitoring()
}
}
void Meter::OnAudioIOMonitor(wxCommandEvent &evt)
void Meter::OnAudioIOStatus(wxCommandEvent &evt)
{
evt.Skip();
if (mMonitoring && !evt.GetInt())
// Don't do anything if we're not the active input meter
if (!IsShownOnScreen())
{
if (!mMeterDisabled){
wxCommandEvent dummy;
OnDisableMeter(dummy);
return;
}
AudacityProject *p = (AudacityProject *) evt.GetEventObject();
mActive = false;
if (evt.GetInt() != 0)
{
if (p == mProject)
{
mActive = true;
if (evt.GetEventType() == EVT_AUDIOIO_MONITOR)
{
mMonitoring = mActive;
}
}
else
{
mMonitoring = false;
}
}
else
{
mMonitoring = false;
}

View File

@ -20,6 +20,7 @@
#include <wx/panel.h>
#include <wx/timer.h>
#include "../Project.h"
#include "../SampleFormat.h"
#include "../Sequence.h"
#include "Ruler.h"
@ -102,7 +103,8 @@ class Meter : public wxPanel
};
Meter(wxWindow* parent, wxWindowID id,
Meter(AudacityProject *,
wxWindow* parent, wxWindowID id,
bool isInput,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
@ -179,7 +181,7 @@ class Meter : public wxPanel
void OnSize(wxSizeEvent &evt);
void OnMouse(wxMouseEvent &evt);
void OnAudioIOMonitor(wxCommandEvent &evt);
void OnAudioIOStatus(wxCommandEvent &evt);
void OnMeterUpdate(wxTimerEvent &evt);
@ -212,6 +214,7 @@ class Meter : public wxPanel
void CreateIcon(int aquaOffset);
wxFont GetFont();
AudacityProject *mProject;
MeterUpdateQueue mQueue;
wxTimer mTimer;
@ -236,6 +239,8 @@ class Meter : public wxPanel
bool mMonitoring;
bool mActive;
int mNumBars;
MeterBar mBar[kMaxMeterBars];