diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 322dcf230..58bd9564c 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -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) diff --git a/src/AudioIO.h b/src/AudioIO.h index 2e9b3de86..b8d825ee9 100644 --- a/src/AudioIO.h +++ b/src/AudioIO.h @@ -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 diff --git a/src/Menus.cpp b/src/Menus.cpp index b590e63df..29d412954 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -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(); diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 8c2242716..3368d56bd 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -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, diff --git a/src/Project.cpp b/src/Project.cpp index 04821a37f..2083ee8be 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -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); } } diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index c55612946..10da5ea5e 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -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 diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 4bc806d3c..bc9ba63fb 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -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; diff --git a/src/toolbars/MeterToolBar.cpp b/src/toolbars/MeterToolBar.cpp index 583ddb9e3..468219831 100644 --- a/src/toolbars/MeterToolBar.cpp +++ b/src/toolbars/MeterToolBar.cpp @@ -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, diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index 6d9b837a8..e88b6ace7 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -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, diff --git a/src/widgets/Meter.cpp b/src/widgets/Meter.cpp index 1ade4d016..419c398d0 100644 --- a/src/widgets/Meter.cpp +++ b/src/widgets/Meter.cpp @@ -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; - // - if (mMeterDisabled) - return; - //wxLogDebug(wxT("Pop: %s"), msg.toString().c_str()); - mT += deltaT; for(j=0; jIsMonitoring()){ 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; } diff --git a/src/widgets/Meter.h b/src/widgets/Meter.h index 56dd9be51..530afc35f 100644 --- a/src/widgets/Meter.h +++ b/src/widgets/Meter.h @@ -20,6 +20,7 @@ #include #include +#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];