From 59d740ad77c231487f32b98a3411912e7662b090 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH] Use a dedicated velocity slider for note tracks This gets rid of the offset rectangle hack that was needed to re-use gain sliders for note track velocities. It also removes the need for changing the style of a single slider. Perhaps most importantly, it fixes link errors regarding GainSlider(int). See https://sourceforge.net/p/audacity/mailman/message/35752524/ for details on why this change is needed and what caused it. --- src/NoteTrack.h | 6 -- src/TrackPanel.cpp | 260 ++++++++++++++++++++++++++------------------- src/TrackPanel.h | 27 ++++- 3 files changed, 173 insertions(+), 120 deletions(-) diff --git a/src/NoteTrack.h b/src/NoteTrack.h index b6d1e5a2a..c0db1bb94 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -177,11 +177,6 @@ class AUDACITY_DLL_API NoteTrack final void StartVScroll(); void VScroll(int start, int end); -#ifdef EXPERIMENTAL_MIDI_OUT - wxRect GetGainPlacementRect() const { return mGainPlacementRect; } - void SetGainPlacementRect(const wxRect &r) { mGainPlacementRect = r; } -#endif - bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override; XMLTagHandler *HandleXMLChild(const wxChar *tag) override; void WriteXML(XMLWriter &xmlFile) const override; @@ -224,7 +219,6 @@ class AUDACITY_DLL_API NoteTrack final int mPitchHeight; int mVisibleChannels; // bit set of visible channels int mLastMidiPosition; - wxRect mGainPlacementRect; }; #endif // USE_MIDI diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 8ccc83a28..7c8e063af 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1182,7 +1182,8 @@ void TrackPanel::HandleInterruptedDrag() IsGainSliding, IsPanSliding, WasOverCutLine, - IsStretching + IsStretching, + IsVelocitySliding */ // The bogus id isn't used anywhere, but may help with debugging. // as this is sending a bogus mouse up. The mouse button is still actually down @@ -4841,7 +4842,7 @@ void TrackPanel::HandleMutingSoloing(wxMouseEvent & event, bool solo) } wxRect buttonRect; - mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton()); + mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton(), t); wxClientDC dc(this); @@ -4906,6 +4907,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) #ifdef EXPERIMENTAL_OUTPUT_DISPLAY bool panZero = false; #endif + wxASSERT(mCapturedTrack->GetKind() == Track::Wave); // On the Mac, we'll lose track capture if the slider dialog // is displayed, but it doesn't hurt to do this for all plats. @@ -4924,20 +4926,15 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) float newValue = slider->Get(); MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too. -#ifdef EXPERIMENTAL_MIDI_OUT - if (capturedTrack->GetKind() == Track::Wave) -#endif - { - const auto wt = static_cast(capturedTrack); // Assume linked track is wave or null - const auto link = static_cast(wt->GetLink()); + const auto link = static_cast(capturedTrack->GetLink()); if (pan) { #ifdef EXPERIMENTAL_OUTPUT_DISPLAY - panZero = wt->SetPan(newValue); + panZero = capturedTrack->SetPan(newValue); #else - wt->SetPan(newValue); + capturedTrack->SetPan(newValue); #endif if (link) link->SetPan(newValue); @@ -4947,51 +4944,57 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) #endif if (pMixerBoard) - pMixerBoard->UpdatePan(wt); + pMixerBoard->UpdatePan(capturedTrack); } else { - wt->SetGain(newValue); + capturedTrack->SetGain(newValue); if (link) link->SetGain(newValue); if (pMixerBoard) - pMixerBoard->UpdateGain(wt); + pMixerBoard->UpdateGain(capturedTrack); } - } -#ifdef EXPERIMENTAL_MIDI_OUT - else { - // mCapturedTrack is not wave... - if (!pan) { - // .. so assume it is note - static_cast(mCapturedTrack)->SetVelocity(newValue); -#ifdef EXPERIMENTAL_MIXER_BOARD - if (pMixerBoard) - // probably should modify UpdateGain to take a track that is - // either a WaveTrack or a NoteTrack. - pMixerBoard->UpdateGain((WaveTrack*)capturedTrack); -#endif - } - } -#endif RefreshTrack(capturedTrack); if (event.ButtonUp()) { -#ifdef EXPERIMENTAL_MIDI_OUT - if (capturedTrack->GetKind() == Track::Wave) { -#endif MakeParentPushState(pan ? _("Moved pan slider") : _("Moved gain slider"), pan ? _("Pan") : _("Gain"), UndoPush::CONSOLIDATE); -#ifdef EXPERIMENTAL_MIDI_OUT - } else { - MakeParentPushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); - } -#endif SetCapturedTrack( NULL ); } } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackPanel::HandleVelocitySlider(wxMouseEvent &event) +{ + wxASSERT(mCapturedTrack->GetKind() == Track::Note); + NoteTrack *capturedTrack = (NoteTrack *) mCapturedTrack; + + LWSlider *slider = mTrackInfo.VelocitySlider(capturedTrack, true); + + slider->OnMouseEvent(event); + + //If we have a double-click, do this... + if (event.LeftDClick()) + mMouseCapture = IsUncaptured; + + float newValue = slider->Get(); + capturedTrack->SetVelocity(newValue); + + MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too. + + if (pMixerBoard) { + pMixerBoard->UpdateVelocity(capturedTrack); + } + RefreshTrack(capturedTrack); + if (event.ButtonUp()) { + MakeParentPushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); + SetCapturedTrack(NULL); + } +} +#endif + // The tracks positions within the list have changed, so update the vertical // ruler size for the track that triggered the event. void TrackPanel::OnTrackListResized(wxCommandEvent & e) @@ -5092,7 +5095,7 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event) { // DM: Check Mute and Solo buttons on WaveTracks: if (MuteSoloFunc(t, rect, event.m_x, event.m_y, false) || - MuteSoloFunc(t, rect, event.m_x, event.m_y, true)) + MuteSoloFunc(t, rect, event.m_x, event.m_y, true)) return; if (GainFunc(t, rect, event, event.m_x, event.m_y)) @@ -5107,21 +5110,11 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event) { wxRect midiRect; #ifdef EXPERIMENTAL_MIDI_OUT - // this is an awful hack: make a NEW rectangle at an offset because - // MuteSoloFunc thinks buttons are located below some text, e.g. - // "Mono, 44100Hz 32-bit float", but this is not true for a Note track - wxRect muteSoloRect(rect); - muteSoloRect.y -= 34; // subtract the height of wave track text - if (MuteSoloFunc(t, muteSoloRect, event.m_x, event.m_y, false) || - MuteSoloFunc(t, muteSoloRect, event.m_x, event.m_y, true)) + if (isleft && (MuteSoloFunc(t, rect, event.m_x, event.m_y, false) || + MuteSoloFunc(t, rect, event.m_x, event.m_y, true))) return; - // this is a similar hack: GainFunc expects a Wave track slider, so it's - // looking in the wrong place. We pass it a bogus rectangle created when - // the slider was placed to "fake" GainFunc into finding the slider in - // its actual location. - if (GainFunc(t, ((NoteTrack *) t)->GetGainPlacementRect(), - event, event.m_x, event.m_y)) + if (isleft && VelocityFunc(t, rect, event, event.m_x, event.m_y)) return; #endif mTrackInfo.GetTrackControlsRect(rect, midiRect); @@ -5287,6 +5280,23 @@ bool TrackPanel::PanFunc(Track * t, wxRect rect, wxMouseEvent &event, return true; } +#ifdef EXPERIMENTAL_MIDI_OUT +bool TrackPanel::VelocityFunc(Track * t, wxRect rect, wxMouseEvent &event, + int x, int y) +{ + wxRect sliderRect; + mTrackInfo.GetVelocityRect(rect, sliderRect); + if (!sliderRect.Contains(x, y)) + return false; + + SetCapturedTrack(t, IsVelocitySliding); + mCapturedRect = rect; + HandleVelocitySlider(event); + + return true; +} +#endif + /// Mute or solo the given track (t). If solo is true, we're /// soloing, otherwise we're muting. Basically, check and see /// whether x and y fall within the area of the appropriate button. @@ -5294,7 +5304,7 @@ bool TrackPanel::MuteSoloFunc(Track * t, wxRect rect, int x, int y, bool solo) { wxRect buttonRect; - mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton()); + mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton(), t); if (!buttonRect.Contains(x, y)) return false; @@ -6182,6 +6192,11 @@ try case IsPanSliding: HandleSliders(event, true); break; +#ifdef EXPERIMENTAL_MIDI_OUT + case IsVelocitySliding: + HandleVelocitySlider(event); + break; +#endif case IsMinimizing: HandleMinimizing(event); break; @@ -7222,11 +7237,6 @@ void TrackPanel::DrawOutside(Track * t, wxDC * dc, const wxRect & rec, #ifdef USE_MIDI else if (bIsNote) { - // Note tracks do not have text, e.g. "Mono, 44100Hz, 32-bit float", so - // Mute & Solo button goes higher. To preserve existing AudioTrack code, - // we move the buttons up by pretending track is higher (at lower y) - rect.y -= 34; - rect.height += 34; wxRect midiRect; mTrackInfo.GetTrackControlsRect(trackRect, midiRect); // Offset by height of Solo/Mute buttons: @@ -7234,36 +7244,22 @@ void TrackPanel::DrawOutside(Track * t, wxDC * dc, const wxRect & rec, midiRect.height -= 21; // allow room for minimize button at bottom #ifdef EXPERIMENTAL_MIDI_OUT - // the offset 2 is just to leave a little space between channel buttons - // and velocity slider (if any) - int h = ((NoteTrack *) t)->DrawLabelControls(*dc, midiRect) + 2; + ((NoteTrack *)t)->DrawLabelControls(*dc, midiRect); - // Draw some lines for MuteSolo buttons: - if (rect.height > 84) { - AColor::Line(*dc, rect.x+48 , rect.y+50, rect.x+48, rect.y + 66); - // bevel below mute/solo - AColor::Line(*dc, rect.x, rect.y + 66, mTrackInfo.GetTrackInfoWidth(), rect.y + 66); - } - mTrackInfo.DrawMuteSolo(dc, rect, t, - (captured && mMouseCapture == IsMuting), false, HasSoloButton()); - mTrackInfo.DrawMuteSolo(dc, rect, t, - (captured && mMouseCapture == IsSoloing), true, HasSoloButton()); + // Draw some lines for MuteSolo buttons (normally handled by DrawBordersWithin but not done for note tracks) + if (rect.height > 48) { + // Note: offset up by 34 units + AColor::Line(*dc, rect.x + 48, rect.y + 16, rect.x + 48, rect.y + 32); // between mute/solo + AColor::Line(*dc, rect.x, rect.y + 32, kTrackInfoWidth, rect.y + 32); // below mute/solo + } + mTrackInfo.DrawMuteSolo(dc, rect, t, + (captured && mMouseCapture == IsMuting), false, HasSoloButton()); + mTrackInfo.DrawMuteSolo(dc, rect, t, + (captured && mMouseCapture == IsSoloing), true, HasSoloButton()); - // place a volume control below channel buttons (this will - // control an offset to midi velocity). - // DrawVelocitySlider places slider assuming this is a Wave track - // and using a large offset to leave room for other things, - // so here we make a fake rectangle as if it is for a Wave - // track, but it is offset to place the slider properly in - // a Note track. This whole placement thing should be redesigned - // to lay out different types of tracks and controls - wxRect gr; // gr is gain rectangle where slider is drawn - mTrackInfo.GetGainRect(rect, gr); - rect.y = rect.y + h - gr.y; // ultimately want slider at rect.y + h - rect.height = rect.height - h + gr.y; - // save for mouse hit detect: - ((NoteTrack *) t)->SetGainPlacementRect(rect); - mTrackInfo.DrawVelocitySlider(dc, (NoteTrack *) t, rect); + // Place a volume control below channel buttons (this will + // control an offset to midi velocity). + mTrackInfo.DrawVelocitySlider(dc, (NoteTrack *)t, rect, captured); #endif } #endif // USE_MIDI @@ -9015,6 +9011,22 @@ TrackInfo::TrackInfo(TrackPanel * pParentIn) PAN_SLIDER); mPanCaptured->SetDefaultValue(0.0); +#ifdef EXPERIMENTAL_MIDI_OUT + GetVelocityRect(rect, sliderRect); + + /* i18n-hint: Title of the Velocity slider, used to adjust the volume of note tracks */ + mVelocity = std::make_unique(pParent, _("Velocity"), + wxPoint(sliderRect.x, sliderRect.y), + wxSize(sliderRect.width, sliderRect.height), + VEL_SLIDER); + mVelocity->SetDefaultValue(0.0); + mVelocityCaptured = std::make_unique(pParent, _("Velocity"), + wxPoint(sliderRect.x, sliderRect.y), + wxSize(sliderRect.width, sliderRect.height), + VEL_SLIDER); + mVelocityCaptured->SetDefaultValue(0.0); +#endif + UpdatePrefs(); } @@ -9043,10 +9055,20 @@ void TrackInfo::GetTitleBarRect(const wxRect & rect, wxRect & dest) const dest.height = kTrackInfoBtnSize; } -void TrackInfo::GetMuteSoloRect(const wxRect & rect, wxRect & dest, bool solo, bool bHasSoloButton) const +void TrackInfo::GetMuteSoloRect(const wxRect & rect, wxRect & dest, bool solo, bool bHasSoloButton, const Track *pTrack) const { - dest.x = rect.x ; + dest.x = rect.x; +#ifdef EXPERIMENTAL_MIDI_OUT + if (pTrack->GetKind() == Track::Note) + dest.y = rect.y + 16; + else + { + wxASSERT(pTrack->GetKind() == Track::Wave); + dest.y = rect.y + 50; + } +#else dest.y = rect.y + 50; +#endif dest.width = 48; dest.height = kTrackInfoBtnSize; @@ -9076,6 +9098,16 @@ void TrackInfo::GetPanRect(const wxRect & rect, wxRect & dest) const dest.height = 25; } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackInfo::GetVelocityRect(const wxRect & rect, wxRect & dest) const +{ + dest.x = rect.x + 7; + dest.y = rect.y + 100; + dest.width = 84; + dest.height = 25; +} +#endif + void TrackInfo::GetMinimizeRect(const wxRect & rect, wxRect &dest) const { const int kBlankWidth = kTrackInfoBtnSize + 4; @@ -9264,7 +9296,7 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, wxRect bev; if( solo && !bHasSoloButton ) return; - GetMuteSoloRect(rect, bev, solo, bHasSoloButton); + GetMuteSoloRect(rect, bev, solo, bHasSoloButton, t); bev.Inflate(-1, -1); if (bev.y + bev.height >= rect.y + rect.height - 19) @@ -9342,27 +9374,6 @@ void TrackInfo::DrawMinimize(wxDC * dc, const wxRect & rect, Track * t, bool dow AColor::BevelTrackInfo(*dc, !down, bev); } -#ifdef EXPERIMENTAL_MIDI_OUT -void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect) const -{ - wxRect gainRect; - int index = t->GetIndex(); - - //EnsureSufficientSliders(index); - - GetGainRect(rect, gainRect); - if (gainRect.y + gainRect.height < rect.y + rect.height - 19) { - auto &gain = mGain; // mGains[index]; - gain->SetStyle(VEL_SLIDER); - GainSlider(index)->Move(wxPoint(gainRect.x, gainRect.y)); - GainSlider(index)->Set(t->GetVelocity()); - GainSlider(index)->OnPaint(*dc - // , t->GetSelected() - ); - } -} -#endif - void TrackInfo::DrawSliders(wxDC *dc, WaveTrack *t, wxRect rect, bool captured) const { wxRect sliderRect; @@ -9378,6 +9389,18 @@ void TrackInfo::DrawSliders(wxDC *dc, WaveTrack *t, wxRect rect, bool captured) } } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect, bool captured) const +{ + wxRect sliderRect; + + GetVelocityRect(rect, sliderRect); + if (sliderRect.y + sliderRect.height < rect.y + rect.height - 19) { + VelocitySlider(t, captured)->OnPaint(*dc); + } +} +#endif + LWSlider * TrackInfo::GainSlider(WaveTrack *t, bool captured) const { wxRect rect(kLeftInset, t->GetY() - pParent->GetViewInfo()->vpos + kTopInset, 1, t->GetHeight()); @@ -9412,6 +9435,25 @@ LWSlider * TrackInfo::PanSlider(WaveTrack *t, bool captured) const return (captured ? mPanCaptured : mPan).get(); } +#ifdef EXPERIMENTAL_MIDI_OUT +LWSlider * TrackInfo::VelocitySlider(NoteTrack *t, bool captured) const +{ + wxRect rect(kLeftInset, t->GetY() - pParent->GetViewInfo()->vpos + kTopInset, 1, t->GetHeight()); + wxRect sliderRect; + GetVelocityRect(rect, sliderRect); + + wxPoint pos = sliderRect.GetPosition(); + float velocity = t->GetVelocity(); + + mVelocity->Move(pos); + mVelocity->Set(velocity); + mVelocityCaptured->Move(pos); + mVelocityCaptured->Set(velocity); + + return (captured ? mVelocityCaptured : mVelocity).get(); +} +#endif + void TrackInfo::UpdatePrefs() { // Calculation of best font size depends on language, so it should be redone in case diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 76af1ecc1..2f0ba0841 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -92,10 +92,10 @@ private: void DrawTitleBar(wxDC * dc, const wxRect & rect, Track * t, bool down) const; void DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, bool down, bool solo, bool bHasSoloButton) const; void DrawVRuler(wxDC * dc, const wxRect & rect, Track * t) const; -#ifdef EXPERIMENTAL_MIDI_OUT - void DrawVelocitySlider(wxDC * dc, NoteTrack *t, wxRect rect) const ; -#endif void DrawSliders(wxDC * dc, WaveTrack *t, wxRect rect, bool captured) const; +#ifdef EXPERIMENTAL_MIDI_OUT + void DrawVelocitySlider(wxDC * dc, NoteTrack *t, wxRect rect, bool captured) const; +#endif // Draw the minimize button *and* the sync-lock track icon, if necessary. void DrawMinimize(wxDC * dc, const wxRect & rect, Track * t, bool down) const; @@ -103,9 +103,13 @@ private: void GetTrackControlsRect(const wxRect & rect, wxRect &dest) const; void GetCloseBoxRect(const wxRect & rect, wxRect &dest) const; void GetTitleBarRect(const wxRect & rect, wxRect &dest) const; - void GetMuteSoloRect(const wxRect & rect, wxRect &dest, bool solo, bool bHasSoloButton) const; + void GetMuteSoloRect(const wxRect & rect, wxRect &dest, bool solo, bool bHasSoloButton, + const Track *pTrack) const; void GetGainRect(const wxRect & rect, wxRect &dest) const; void GetPanRect(const wxRect & rect, wxRect &dest) const; +#ifdef EXPERIMENTAL_MIDI_OUT + void GetVelocityRect(const wxRect & rect, wxRect &dest) const; +#endif void GetMinimizeRect(const wxRect & rect, wxRect &dest) const; void GetSyncLockIconRect(const wxRect & rect, wxRect &dest) const; @@ -114,7 +118,7 @@ public: LWSlider * PanSlider(WaveTrack *t, bool captured = false) const; #ifdef EXPERIMENTAL_MIDI_OUT - LWSlider *GainSlider(int index) const; + LWSlider * VelocitySlider(NoteTrack *t, bool captured = false) const; #endif private: @@ -124,6 +128,9 @@ private: wxFont mFont; std::unique_ptr mGainCaptured, mPanCaptured, mGain, mPan; +#ifdef EXPERIMENTAL_MIDI_OUT + std::unique_ptr mVelocityCaptured, mVelocity; +#endif friend class TrackPanel; }; @@ -415,6 +422,9 @@ protected: virtual void HandleMutingSoloing(wxMouseEvent & event, bool solo); virtual void HandleMinimizing(wxMouseEvent & event); virtual void HandleSliders(wxMouseEvent &event, bool pan); +#ifdef EXPERIMENTAL_MIDI_OUT + virtual void HandleVelocitySlider(wxMouseEvent &event); +#endif // These *Func methods are used in TrackPanel::HandleLabelClick to set up @@ -434,6 +444,10 @@ protected: int x, int y); virtual bool PanFunc(Track * t, wxRect rect, wxMouseEvent &event, int x, int y); +#ifdef EXPERIMENTAL_MIDI_OUT + virtual bool VelocityFunc(Track * t, wxRect rect, wxMouseEvent &event, + int x, int y); +#endif virtual void MakeParentRedrawScrollbars(); @@ -747,6 +761,9 @@ protected: IsStretching, #endif IsZooming, +#ifdef EXPERIMENTAL_MIDI_OUT + IsVelocitySliding, +#endif };