From 59d740ad77c231487f32b98a3411912e7662b090 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 1/2] 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 }; From 1c93198d088f3f897fe318e9714d3dff28216f20 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 2/2] Re-implement note tracks in MixerBoard This commit adds note tracks into the mixerboard. It's done as a separate slider this time instead of via subclasses (as PRL requested), so which should be easier to use. This also changes some of the gaurds to EXPERIMENTAL_MIDI_OUT from USE_MIDI, as it's meaningless to have the note track code in mixerboard when it cannot do anything (depends on methods that exist behind EXPERIMENTAL_MIDI_OUT). --- src/Menus.cpp | 6 +- src/MixerBoard.cpp | 109 +++++++++++++++++++++++++------------ src/MixerBoard.h | 19 +++++++ src/commands/CommandFlag.h | 1 + 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 18c4bf000..aaa3f1053 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -728,7 +728,7 @@ void AudacityProject::CreateMenusAndCommands() AudioIONotBusyFlag); c->AddItem(wxT("Karaoke"), _("&Karaoke..."), FN(OnKaraoke), LabelTracksExistFlag, LabelTracksExistFlag); - c->AddItem(wxT("MixerBoard"), _("&Mixer Board..."), FN(OnMixerBoard), WaveTracksExistFlag, WaveTracksExistFlag); + c->AddItem(wxT("MixerBoard"), _("&Mixer Board..."), FN(OnMixerBoard), PlayableTracksExistFlag, PlayableTracksExistFlag); c->AddSeparator(); @@ -1836,6 +1836,7 @@ CommandFlag AudacityProject::GetUpdateFlags(bool checkActive) } else if (t->GetKind() == Track::Wave) { flags |= WaveTracksExistFlag; + flags |= PlayableTracksExistFlag; if (t->GetSelected()) { flags |= TracksSelectedFlag; if (t->GetLinked()) { @@ -1853,6 +1854,9 @@ CommandFlag AudacityProject::GetUpdateFlags(bool checkActive) NoteTrack *nt = (NoteTrack *) t; flags |= NoteTracksExistFlag; +#ifdef EXPERIMENTAL_MIDI_OUT + flags |= PlayableTracksExistFlag; +#endif if (nt->GetSelected()) { flags |= TracksSelectedFlag; diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 2538e85fe..053bcf520 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -24,7 +24,9 @@ #include "AColor.h" #include "AudioIO.h" +#ifdef USE_MIDI #include "NoteTrack.h" +#endif #include "Project.h" #include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER @@ -137,6 +139,9 @@ enum { ID_BITMAPBUTTON_MUSICAL_INSTRUMENT = 13000, ID_SLIDER_PAN, ID_SLIDER_GAIN, +#ifdef EXPERIMENTAL_MIDI_OUT + ID_SLIDER_VELOCITY, +#endif ID_TOGGLEBUTTON_MUTE, ID_TOGGLEBUTTON_SOLO, }; @@ -148,6 +153,9 @@ BEGIN_EVENT_TABLE(MixerTrackCluster, wxPanelWrapper) EVT_BUTTON(ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, MixerTrackCluster::OnButton_MusicalInstrument) EVT_SLIDER(ID_SLIDER_PAN, MixerTrackCluster::OnSlider_Pan) EVT_SLIDER(ID_SLIDER_GAIN, MixerTrackCluster::OnSlider_Gain) +#ifdef EXPERIMENTAL_MIDI_OUT + EVT_SLIDER(ID_SLIDER_VELOCITY, MixerTrackCluster::OnSlider_Velocity) +#endif //v EVT_COMMAND_SCROLL(ID_SLIDER_GAIN, MixerTrackCluster::OnSliderScroll_Gain) EVT_COMMAND(ID_TOGGLEBUTTON_MUTE, wxEVT_COMMAND_BUTTON_CLICKED, MixerTrackCluster::OnButton_Mute) EVT_COMMAND(ID_TOGGLEBUTTON_SOLO, wxEVT_COMMAND_BUTTON_CLICKED, MixerTrackCluster::OnButton_Solo) @@ -184,37 +192,33 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, // mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor()); - // gain slider at left + // gain and velocity sliders at left (both in same place) ctrlPos.x = kDoubleInset; ctrlPos.y += TRACK_NAME_HEIGHT + kDoubleInset; const int nGainSliderHeight = size.GetHeight() - ctrlPos.y - kQuadrupleInset; ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight); -#ifdef USE_MIDI - if (GetNote()) { - mSlider_Gain = - safenew MixerTrackSlider( - this, ID_SLIDER_GAIN, - /* i18n-hint: title of the MIDI Velocity slider */ - _("Velocity"), - ctrlPos, ctrlSize, VEL_SLIDER, true, - true, 0.0, wxVERTICAL); - } - else -#endif - mSlider_Gain = - safenew MixerTrackSlider( - this, ID_SLIDER_GAIN, - /* i18n-hint: title of the Gain slider, used to adjust the volume */ - _("Gain"), - ctrlPos, ctrlSize, DB_SLIDER, true, - true, 0.0, wxVERTICAL); - + mSlider_Gain = + safenew MixerTrackSlider( + this, ID_SLIDER_GAIN, + /* i18n-hint: title of the Gain slider, used to adjust the volume */ + _("Gain"), + ctrlPos, ctrlSize, DB_SLIDER, true, + true, 0.0, wxVERTICAL); mSlider_Gain->SetName(_("Gain")); - this->UpdateGain(); - +#ifdef EXPERIMENTAL_MIDI_OUT + mSlider_Velocity = + safenew MixerTrackSlider( + this, ID_SLIDER_VELOCITY, + /* i18n-hint: title of the MIDI Velocity slider */ + _("Velocity"), + ctrlPos, ctrlSize, VEL_SLIDER, true, + true, 0.0, wxVERTICAL); + mSlider_Velocity->SetName(_("Velocity")); + this->UpdateVelocity(); +#endif // other controls and meter at right @@ -329,7 +333,7 @@ WaveTrack *MixerTrackCluster::GetRight() const return nullptr; } -#ifdef USE_MIDI +#ifdef EXPERIMENTAL_MIDI_OUT NoteTrack *MixerTrackCluster::GetNote() const { return dynamic_cast< NoteTrack * >( mTrack ); @@ -361,6 +365,9 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a TRACK_NAME_HEIGHT + kDoubleInset) - // mStaticText_TrackName + margin kQuadrupleInset; // margin below gain slider mSlider_Gain->SetSize(-1, nGainSliderHeight); +#ifdef EXPERIMENTAL_MIDI_OUT + mSlider_Velocity->SetSize(-1, nGainSliderHeight); +#endif bool bSoloNone = mProject->IsSoloNone(); @@ -384,10 +391,6 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) float fValue = mSlider_Gain->Get(); if (GetWave()) GetWave()->SetGain(fValue); -#ifdef EXPERIMENTAL_MIDI_OUT - else - GetNote()->SetVelocity(fValue); -#endif if (GetRight()) GetRight()->SetGain(fValue); @@ -397,6 +400,20 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE ); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::HandleSliderVelocity(const bool bWantPushState /*= false*/) +{ + float fValue = mSlider_Velocity->Get(); + if (GetNote()) + GetNote()->SetVelocity(fValue); + + // Update the TrackPanel correspondingly. + mProject->RefreshTPTrack(mTrack); + if (bWantPushState) + mProject->TP_PushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); +} +#endif + void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/) { float fValue = mSlider_Pan->Get(); @@ -462,28 +479,33 @@ void MixerTrackCluster::UpdateSolo() void MixerTrackCluster::UpdatePan() { -#ifdef EXPERIMENTAL_MIDI_OUT if (!GetWave()) { mSlider_Pan->Hide(); return; } -#endif mSlider_Pan->Set(GetWave()->GetPan()); } void MixerTrackCluster::UpdateGain() { -#ifdef EXPERIMENTAL_MIDI_OUT if (!GetWave()) { - mSlider_Gain->SetStyle(VEL_SLIDER); - mSlider_Gain->Set(GetNote()->GetVelocity()); + mSlider_Gain->Hide(); return; } - mSlider_Gain->SetStyle(DB_SLIDER); -#endif mSlider_Gain->Set(GetWave()->GetGain()); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::UpdateVelocity() +{ + if (!GetNote()) { + mSlider_Velocity->Hide(); + return; + } + mSlider_Velocity->Set(GetNote()->GetVelocity()); +} +#endif + void MixerTrackCluster::UpdateMeter(const double t0, const double t1) { // NoteTracks do not (currently) register on meters. It would probably be @@ -696,6 +718,13 @@ void MixerTrackCluster::OnSlider_Gain(wxCommandEvent& WXUNUSED(event)) this->HandleSliderGain(); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::OnSlider_Velocity(wxCommandEvent& WXUNUSED(event)) +{ + this->HandleSliderVelocity(); +} +#endif + //v void MixerTrackCluster::OnSliderScroll_Gain(wxScrollEvent& WXUNUSED(event)) //{ //int sliderValue = (int)(mSlider_Gain->Get()); //v mSlider_Gain->GetValue(); @@ -1209,6 +1238,16 @@ void MixerBoard::UpdateGain(const PlayableTrack* pTrack) pMixerTrackCluster->UpdateGain(); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerBoard::UpdateVelocity(const PlayableTrack* pTrack) +{ + MixerTrackCluster* pMixerTrackCluster; + FindMixerTrackCluster(pTrack, &pMixerTrackCluster); + if (pMixerTrackCluster) + pMixerTrackCluster->UpdateVelocity(); +} +#endif + void MixerBoard::UpdateMeters(const double t1, const bool bLoopedPlay) { if (!this->IsShown() || (t1 == BAD_STREAM_TIME)) diff --git a/src/MixerBoard.h b/src/MixerBoard.h index ae8f7ad58..56f99d0f3 100644 --- a/src/MixerBoard.h +++ b/src/MixerBoard.h @@ -64,7 +64,9 @@ class Meter; class MixerBoard; class Track; +#ifdef USE_MIDI class NoteTrack; +#endif class PlayableTrack; class WaveTrack; @@ -81,13 +83,18 @@ public: WaveTrack *GetWave() const; WaveTrack *GetRight() const; +#ifdef EXPERIMENTAL_MIDI_OUT NoteTrack *GetNote() const; +#endif void UpdatePrefs(); void HandleResize(); // For wxSizeEvents, update gain slider and meter. void HandleSliderGain(const bool bWantPushState = false); +#ifdef EXPERIMENTAL_MIDI_OUT + void HandleSliderVelocity(const bool bWantPushState = false); +#endif void HandleSliderPan(const bool bWantPushState = false); void ResetMeter(const bool bResetClipping); @@ -99,6 +106,9 @@ public: void UpdateSolo(); void UpdatePan(); void UpdateGain(); +#ifdef EXPERIMENTAL_MIDI_OUT + void UpdateVelocity(); +#endif void UpdateMeter(const double t0, const double t1); private: @@ -113,6 +123,9 @@ private: void OnButton_MusicalInstrument(wxCommandEvent& event); void OnSlider_Gain(wxCommandEvent& event); +#ifdef EXPERIMENTAL_MIDI_OUT + void OnSlider_Velocity(wxCommandEvent& event); +#endif void OnSlider_Pan(wxCommandEvent& event); void OnButton_Mute(wxCommandEvent& event); void OnButton_Solo(wxCommandEvent& event); @@ -133,6 +146,9 @@ private: AButton* mToggleButton_Solo; MixerTrackSlider* mSlider_Pan; MixerTrackSlider* mSlider_Gain; +#ifdef EXPERIMENTAL_MIDI_OUT + MixerTrackSlider* mSlider_Velocity; +#endif Meter* mMeter; public: @@ -222,6 +238,9 @@ public: void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks. void UpdatePan(const PlayableTrack* pTrack); void UpdateGain(const PlayableTrack* pTrack); +#ifdef EXPERIMENTAL_MIDI_OUT + void UpdateVelocity(const PlayableTrack* pTrack); +#endif void UpdateMeters(const double t1, const bool bLoopedPlay); diff --git a/src/commands/CommandFlag.h b/src/commands/CommandFlag.h index e88123691..6ae14d055 100644 --- a/src/commands/CommandFlag.h +++ b/src/commands/CommandFlag.h @@ -54,6 +54,7 @@ enum CommandFlag : unsigned long long PausedFlag = 0x200000000ULL, // jkc NotPausedFlag = 0x400000000ULL, // jkc HasWaveDataFlag = 0x800000000ULL, // jkc + PlayableTracksExistFlag = 0x1000000000ULL, NoFlagsSpecifed = ~0ULL };