Audacity  3.0.3
WaveformVRulerControls.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 WaveformVRulerControls.cpp
6 
7 Paul Licameli split from WaveTrackVRulerControls.cpp
8 
9 **********************************************************************/
10 
11 #include "WaveformVRulerControls.h"
12 
13 #include "WaveformVZoomHandle.h"
15 
16 #include "NumberScale.h"
17 #include "../../../../ProjectHistory.h"
18 #include "../../../../RefreshCode.h"
19 #include "../../../../TrackPanelMouseEvent.h"
20 #include "../../../../UIHandle.h"
21 #include "../../../../WaveTrack.h"
22 #include "../../../../prefs/WaveformSettings.h"
23 #include "../../../../widgets/Ruler.h"
24 
26 
27 std::vector<UIHandlePtr> WaveformVRulerControls::HitTest(
28  const TrackPanelMouseState &st,
29  const AudacityProject *pProject)
30 {
31  std::vector<UIHandlePtr> results;
32 
33  if ( st.state.GetX() <= st.rect.GetRight() - kGuard ) {
34  auto pTrack = FindTrack()->SharedPointer<WaveTrack>( );
35  if (pTrack) {
36  auto result = std::make_shared<WaveformVZoomHandle>(
37  pTrack, st.rect, st.state.m_y );
38  result = AssignUIHandlePtr(mVZoomHandle, result);
39  results.push_back(result);
40  }
41  }
42 
43  auto more = TrackVRulerControls::HitTest(st, pProject);
44  std::copy(more.begin(), more.end(), std::back_inserter(results));
45 
46  return results;
47 }
48 
50  const TrackPanelMouseEvent &evt, AudacityProject *pProject)
51 {
52  using namespace RefreshCode;
53  const auto pTrack = FindTrack();
54  if (!pTrack)
55  return RefreshNone;
56  const auto wt = static_cast<WaveTrack*>(pTrack.get());
57  return DoHandleWheelRotation( evt, pProject, wt );
58 }
59 
61  const TrackPanelMouseEvent &evt, AudacityProject *pProject, WaveTrack *wt)
62 {
63  using namespace RefreshCode;
64  const wxMouseEvent &event = evt.event;
65 
66  if (!(event.ShiftDown() || event.CmdDown()))
67  return RefreshNone;
68 
69  // Always stop propagation even if the ruler didn't change. The ruler
70  // is a narrow enough target.
71  evt.event.Skip(false);
72 
73  auto steps = evt.steps;
74 
75  using namespace WaveTrackViewConstants;
76  const bool isDB =
78  // Special cases for Waveform dB only.
79  // Set the bottom of the dB scale but only if it's visible
80  if (isDB && event.ShiftDown() && event.CmdDown()) {
81  float min, max;
82  wt->GetDisplayBounds(&min, &max);
83  if (!(min < 0.0 && max > 0.0))
84  return RefreshNone;
85 
87  wt->GetWaveformSettings();
88  float olddBRange = settings.dBRange;
89  for (auto channel : TrackList::Channels(wt)) {
90  WaveformSettings &channelSettings =
91  channel->GetWaveformSettings();
92  if (steps < 0)
93  // Zoom out
94  channelSettings.NextLowerDBRange();
95  else
96  channelSettings.NextHigherDBRange();
97  }
98 
99  float newdBRange = settings.dBRange;
100 
101  // Is y coordinate within the rectangle half-height centered about
102  // the zero level?
103  const auto &rect = evt.rect;
104  const auto zeroLevel = wt->ZeroLevelYCoordinate(rect);
105  const bool fixedMagnification =
106  (4 * std::abs(event.GetY() - zeroLevel) < rect.GetHeight());
107 
108  if (fixedMagnification) {
109  // Vary the db limit without changing
110  // magnification; that is, peaks and troughs move up and down
111  // rigidly, as parts of the wave near zero are exposed or hidden.
112  const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
113  max = std::min(extreme, max * olddBRange / newdBRange);
114  min = std::max(-extreme, min * olddBRange / newdBRange);
115  for (auto channel : TrackList::Channels(wt)) {
116  channel->SetLastdBRange();
117  channel->SetDisplayBounds(min, max);
118  }
119  }
120  }
121  else if (event.CmdDown() && !event.ShiftDown()) {
122  const int yy = event.m_y;
124  pProject, wt,
125  (steps < 0)
126  ? kZoomOut
127  : kZoomIn,
128  evt.rect, yy, yy, true);
129  }
130  else if (!event.CmdDown() && event.ShiftDown()) {
131  // Scroll some fixed number of pixels, independent of zoom level or track height:
132  static const float movement = 10.0f;
133  const int height = evt.rect.GetHeight();
134  {
135  float topLimit = 2.0;
136  if (isDB) {
137  const float dBRange = wt->GetWaveformSettings().dBRange;
138  topLimit = (LINEAR_TO_DB(topLimit) + dBRange) / dBRange;
139  }
140  const float bottomLimit = -topLimit;
141  float top, bottom;
142  wt->GetDisplayBounds(&bottom, &top);
143  const float range = top - bottom;
144  const float delta = range * steps * movement / height;
145  float newTop = std::min(topLimit, top + delta);
146  const float newBottom = std::max(bottomLimit, newTop - range);
147  newTop = std::min(topLimit, newBottom + range);
148  for (auto channel : TrackList::Channels(wt))
149  channel->SetDisplayBounds(newBottom, newTop);
150  }
151  }
152  else
153  return RefreshNone;
154 
155  ProjectHistory::Get( *pProject ).ModifyState(true);
156 
157  return RefreshCell | UpdateVRuler;
158 }
159 
161  TrackPanelDrawingContext &context,
162  const wxRect &rect_, unsigned iPass )
163 {
164  TrackVRulerControls::Draw( context, rect_, iPass );
165  WaveTrackVRulerControls::DoDraw( *this, context, rect_, iPass );
166 }
167 
168 void WaveformVRulerControls::UpdateRuler( const wxRect &rect )
169 {
170  const auto wt = std::static_pointer_cast< WaveTrack >( FindTrack() );
171  if (!wt)
172  return;
173  DoUpdateVRuler( rect, wt.get() );
174 }
175 
177  const wxRect &rect, const WaveTrack *wt )
178 {
179  auto vruler = &WaveTrackVRulerControls::ScratchRuler();
180 
181  // All waves have a ruler in the info panel
182  // The ruler needs a bevelled surround.
183  const float dBRange =
185 
186  WaveformSettings::ScaleType scaleType =
188 
189  if (scaleType == WaveformSettings::stLinear) {
190  // Waveform
191 
192  float min, max;
193  wt->GetDisplayBounds(&min, &max);
194  if (wt->GetLastScaleType() != scaleType &&
195  wt->GetLastScaleType() != -1)
196  {
197  // do a translation into the linear space
198  wt->SetLastScaleType();
199  wt->SetLastdBRange();
200  float sign = (min >= 0 ? 1 : -1);
201  if (min != 0.) {
202  min = DB_TO_LINEAR(fabs(min) * dBRange - dBRange);
203  if (min < 0.0)
204  min = 0.0;
205  min *= sign;
206  }
207  sign = (max >= 0 ? 1 : -1);
208 
209  if (max != 0.) {
210  max = DB_TO_LINEAR(fabs(max) * dBRange - dBRange);
211  if (max < 0.0)
212  max = 0.0;
213  max *= sign;
214  }
215  wt->SetDisplayBounds(min, max);
216  }
217 
218  vruler->SetDbMirrorValue( 0.0 );
219  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
220  vruler->SetOrientation(wxVERTICAL);
221  vruler->SetRange(max, min);
222  vruler->SetFormat(Ruler::RealFormat);
223  vruler->SetUnits({});
224  vruler->SetLabelEdges(false);
225  vruler->SetLog(false);
226  }
227  else {
228  wxASSERT(scaleType == WaveformSettings::stLogarithmic);
230 
231  vruler->SetUnits({});
232 
233  float min, max;
234  wt->GetDisplayBounds(&min, &max);
235  float lastdBRange;
236 
237  if (wt->GetLastScaleType() != scaleType &&
238  wt->GetLastScaleType() != -1)
239  {
240  // do a translation into the dB space
241  wt->SetLastScaleType();
242  wt->SetLastdBRange();
243  float sign = (min >= 0 ? 1 : -1);
244  if (min != 0.) {
245  min = (LINEAR_TO_DB(fabs(min)) + dBRange) / dBRange;
246  if (min < 0.0)
247  min = 0.0;
248  min *= sign;
249  }
250  sign = (max >= 0 ? 1 : -1);
251 
252  if (max != 0.) {
253  max = (LINEAR_TO_DB(fabs(max)) + dBRange) / dBRange;
254  if (max < 0.0)
255  max = 0.0;
256  max *= sign;
257  }
258  wt->SetDisplayBounds(min, max);
259  }
260  else if (dBRange != (lastdBRange = wt->GetLastdBRange())) {
261  wt->SetLastdBRange();
262  // Remap the max of the scale
263  float newMax = max;
264 
265  // This commented out code is problematic.
266  // min and max may be correct, and this code cause them to change.
267 #ifdef ONLY_LABEL_POSITIVE
268  const float sign = (max >= 0 ? 1 : -1);
269  if (max != 0.) {
270 
271  // Ugh, duplicating from TrackPanel.cpp
272 #define ZOOMLIMIT 0.001f
273 
274  const float extreme = LINEAR_TO_DB(2);
275  // recover dB value of max
276  const float dB = std::min(extreme, (float(fabs(max)) * lastdBRange - lastdBRange));
277  // find NEW scale position, but old max may get trimmed if the db limit rises
278  // Don't trim it to zero though, but leave max and limit distinct
279  newMax = sign * std::max(ZOOMLIMIT, (dBRange + dB) / dBRange);
280  // Adjust the min of the scale if we can,
281  // so the db Limit remains where it was on screen, but don't violate extremes
282  if (min != 0.)
283  min = std::max(-extreme, newMax * min / max);
284  }
285 #endif
286  wt->SetDisplayBounds(min, newMax);
287  }
288 
289  // Old code was if ONLY_LABEL_POSITIVE were defined.
290  // it uses the +1 to 0 range only.
291  // the enabled code uses +1 to -1, and relies on set ticks labelling knowing about
292  // the dB scale.
293 #ifdef ONLY_LABEL_POSITIVE
294  if (max > 0) {
295 #endif
296  int top = 0;
297  float topval = 0;
298  int bot = rect.height;
299  float botval = -dBRange;
300 
301 #ifdef ONLY_LABEL_POSITIVE
302  if (min < 0) {
303  bot = top + (int)((max / (max - min))*(bot - top));
304  min = 0;
305  }
306 
307  if (max > 1) {
308  top += (int)((max - 1) / (max - min) * (bot - top));
309  max = 1;
310  }
311 
312  if (max < 1 && max > 0)
313  topval = -((1 - max) * dBRange);
314 
315  if (min > 0) {
316  botval = -((1 - min) * dBRange);
317  }
318 #else
319  topval = -((1 - max) * dBRange);
320  botval = -((1 - min) * dBRange);
321  vruler->SetDbMirrorValue( dBRange );
322 #endif
323  vruler->SetBounds(rect.x, rect.y + top, rect.x + rect.width, rect.y + bot - 1);
324  vruler->SetOrientation(wxVERTICAL);
325  vruler->SetRange(topval, botval);
326 #ifdef ONLY_LABEL_POSITIVE
327  }
328  else
329  vruler->SetBounds(0.0, 0.0, 0.0, 0.0); // A.C.H I couldn't find a way to just disable it?
330 #endif
331  vruler->SetFormat(Ruler::RealLogFormat);
332  vruler->SetLabelEdges(true);
333  vruler->SetLog(false);
334  }
335  vruler->GetMaxSize( &wt->vrulerSize.x, &wt->vrulerSize.y );
336 }
WaveformSettings::scaleType
ScaleType scaleType
Definition: WaveformSettings.h:67
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:124
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
DB_TO_LINEAR
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
TrackPanelMouseEvent::rect
const wxRect & rect
Definition: TrackPanelMouseEvent.h:59
NumberScale.h
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
WaveformSettings::ScaleType
int ScaleType
Definition: WaveformSettings.h:57
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:46
WaveTrackViewConstants
Definition: WaveTrackView.h:17
WaveTrack::SetLastdBRange
void SetLastdBRange() const
Definition: WaveTrack.cpp:315
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
WaveformVRulerControls::~WaveformVRulerControls
~WaveformVRulerControls() override
Ruler::RealFormat
@ RealFormat
Definition: Ruler.h:31
WaveformVZoomHandle.h
TrackPanelMouseState::rect
const wxRect & rect
Definition: TrackPanelMouseEvent.h:39
WaveformVRulerControls::DoUpdateVRuler
static void DoUpdateVRuler(const wxRect &rect, const WaveTrack *wt)
Definition: WaveformVRulerControls.cpp:176
WaveTrack::ZeroLevelYCoordinate
int ZeroLevelYCoordinate(wxRect rect) const
Definition: WaveTrack.cpp:382
WaveformSettings::stLogarithmic
@ stLogarithmic
Definition: WaveformSettings.h:60
WaveformVRulerControls.h
WaveformVRulerControls::HandleWheelRotation
unsigned HandleWheelRotation(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: WaveformVRulerControls.cpp:49
WaveTrackVRulerControls::DoDraw
AUDACITY_DLL_API void DoDraw(TrackVRulerControls &controls, TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Definition: WaveTrackVRulerControls.cpp:32
WaveformVZoomHandle::DoZoom
static void DoZoom(AudacityProject *pProject, WaveTrack *pTrack, WaveTrackViewConstants::ZoomActions ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint)
Definition: WaveformVZoomHandle.cpp:105
WaveformSettings::NextHigherDBRange
void NextHigherDBRange()
Definition: WaveformSettings.cpp:154
RefreshCode::UpdateVRuler
@ UpdateVRuler
Definition: RefreshCode.h:30
WaveTrack::SetDisplayBounds
void SetDisplayBounds(float min, float max) const
Definition: WaveTrack.cpp:326
WaveTrackViewConstants::kZoomIn
@ kZoomIn
Definition: WaveTrackViewConstants.h:77
WaveTrackVRulerControls.h
WaveTrack::GetWaveformSettings
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:811
WaveformVRulerControls::DoHandleWheelRotation
static unsigned DoHandleWheelRotation(const TrackPanelMouseEvent &event, AudacityProject *pProject, WaveTrack *wt)
Definition: WaveformVRulerControls.cpp:60
RefreshCode::RefreshCell
@ RefreshCell
Definition: RefreshCode.h:24
WaveTrack::SetLastScaleType
void SetLastScaleType() const
Definition: WaveTrack.cpp:310
kGuard
const int kGuard
Definition: TrackVRulerControls.h:20
TrackVRulerControls::HitTest
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Definition: TrackVRulerControls.cpp:55
WaveTrack::GetLastdBRange
int GetLastdBRange() const
Definition: WaveTrack.h:549
Ruler::RealLogFormat
@ RealLogFormat
Definition: Ruler.h:32
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
WaveformVRulerControls::mVZoomHandle
std::weak_ptr< WaveformVZoomHandle > mVZoomHandle
Definition: WaveformVRulerControls.h:52
WaveTrackVRulerControls::ScratchRuler
AUDACITY_DLL_API Ruler & ScratchRuler()
Definition: WaveTrackVRulerControls.cpp:26
TrackVRulerControls::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackVRulerControls.cpp:97
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
WaveTrack::GetLastScaleType
int GetLastScaleType() const
Definition: WaveTrack.h:546
WaveformSettings::dBRange
int dBRange
Definition: WaveformSettings.h:68
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
WaveformSettings::NextLowerDBRange
void NextLowerDBRange()
Definition: WaveformSettings.cpp:147
WaveformSettings
Waveform settings, either for one track or as defaults.
Definition: WaveformSettings.h:19
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
WaveTrackViewConstants::kZoomOut
@ kZoomOut
Definition: WaveTrackViewConstants.h:78
WaveformVRulerControls::UpdateRuler
void UpdateRuler(const wxRect &rect) override
Definition: WaveformVRulerControls.cpp:168
LINEAR_TO_DB
#define LINEAR_TO_DB(x)
Definition: MemoryX.h:631
WaveformVRulerControls::HitTest
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *) override
Definition: WaveformVRulerControls.cpp:27
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:151
WaveTrack::GetDisplayBounds
void GetDisplayBounds(float *min, float *max) const
Definition: WaveTrack.cpp:320
WaveformVRulerControls::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: WaveformVRulerControls.cpp:160
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
WaveformSettings::stLinear
@ stLinear
Definition: WaveformSettings.h:59
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
TrackPanelMouseState::state
wxMouseState & state
Definition: TrackPanelMouseEvent.h:38
TrackPanelMouseEvent::steps
double steps
Definition: TrackPanelMouseEvent.h:62
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
Track::vrulerSize
wxSize vrulerSize
Definition: Track.h:354