Audacity 3.2.0
SpectrumVZoomHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5SpectrumVZoomHandle.cpp
6
7Paul Licameli split from WaveTrackVZoomHandle.cpp
8
9**********************************************************************/
10
11
12#include "SpectrumVZoomHandle.h"
13
15
16#include "../../../../HitTestResult.h"
17#include "NumberScale.h"
18#include "Prefs.h"
19#include "ProjectHistory.h"
20#include "../../../../RefreshCode.h"
21#include "../../../../TrackPanelMouseEvent.h"
22#include "../../../../WaveTrack.h"
23#include "../../../../prefs/SpectrogramSettings.h"
24
26(const std::shared_ptr<WaveTrack> &pTrack, const wxRect &rect, int y)
27 : mpTrack{ pTrack } , mZoomStart(y), mZoomEnd(y), mRect(rect)
28{
29}
30
32
34{
35#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
37#endif
38}
39
41{
42 return true;
43}
44
47{
49}
50
52(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
53{
54 using namespace RefreshCode;
55 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
56 if (!pTrack)
57 return Cancelled;
58 return WaveTrackVZoomHandle::DoDrag( evt, pProject, mZoomStart, mZoomEnd );
59}
60
63{
65}
66
68(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
69 wxWindow *pParent)
70{
71 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
73 evt, pProject, pParent, pTrack.get(), mRect,
76}
77
79{
80 // Cancel is implemented! And there is no initial state to restore,
81 // so just return a code.
83}
84
87 const wxRect &rect, unsigned iPass )
88{
89 if (!mpTrack.lock()) //? TrackList::Lock()
90 return;
92 context, rect, iPass, mZoomStart, mZoomEnd );
93}
94
97 const wxRect &rect, const wxRect &panelRect, unsigned iPass )
98{
99 return WaveTrackVZoomHandle::DoDrawingArea( rect, panelRect, iPass );
100}
101
102// ZoomKind says how to zoom.
103// If ZoomStart and ZoomEnd are not equal, this may override
104// the zoomKind and cause a drag-zoom-in.
106 AudacityProject *pProject,
107 WaveTrack *pTrack,
109 const wxRect &rect, int zoomStart, int zoomEnd,
110 bool fixedMousePoint)
111{
112 using namespace WaveTrackViewConstants;
113 static const float ZOOMLIMIT = 0.001f;
114
115 int height = rect.height;
116 int ypos = rect.y;
117
118 // Ensure start and end are in order (swap if not).
119 if (zoomEnd < zoomStart)
120 std::swap( zoomStart, zoomEnd );
121
122 float min, max, minBand = 0;
123 const double rate = pTrack->GetRate();
124 const float halfrate = rate / 2;
125 float maxFreq = 8000.0;
126 const SpectrogramSettings &specSettings = pTrack->GetSpectrogramSettings();
127 NumberScale scale;
128 const bool spectrumLinear =
130
131
132 bool bDragZoom = WaveTrackVZoomHandle::IsDragZooming(zoomStart, zoomEnd);
133 // Add 100 if spectral to separate the kinds of zoom.
134 const int kSpectral = 100;
135
136 // Possibly override the zoom kind.
137 if( bDragZoom )
138 ZoomKind = kZoomInByDrag;
139
140 float top=2.0;
141 float half=0.5;
142
143 {
144 pTrack->GetSpectrumBounds(&min, &max);
145 scale = (specSettings.GetScale(min, max));
146 const auto fftLength = specSettings.GetFFTLength();
147 const float binSize = rate / fftLength;
148 maxFreq = SpectrumMaxFreq.Read();
149 // JKC: Following discussions of Bug 1208 I'm allowing zooming in
150 // down to one bin.
151 // const int minBins =
152 // std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
153 const int minBins = 1;
154 minBand = minBins * binSize;
155 }
156
157 // Compute min and max.
158 switch(ZoomKind)
159 {
160 default:
161 // If we have covered all the cases, this won't happen.
162 // In release builds Audacity will ignore the zoom.
163 wxFAIL_MSG("Zooming Case not implemented by Audacity");
164 break;
165
166 // VZooming on spectral we don't implement the other zoom presets.
167 // They are also not in the menu.
168 case kZoomReset:
169 {
170 // Zoom out to normal level.
171 min = spectrumLinear ? 0.0f : 1.0f;
172 max = maxFreq;
173 }
174 break;
175 case kZoom1to1:
176 case kZoomDiv2:
177 case kZoomTimes2:
178 case kZoomHalfWave:
179 {
180 // Zoom out full
181 min = spectrumLinear ? 0.0f : 1.0f;
182 max = halfrate;
183 }
184 break;
185 case kZoomInByDrag:
186 {
187 double xmin = 1 - (zoomEnd - ypos) / (float)height;
188 double xmax = 1 - (zoomStart - ypos) / (float)height;
189 const float middle = (xmin + xmax) / 2;
190 const float middleValue = scale.PositionToValue(middle);
191
192 min = std::max(spectrumLinear ? 0.0f : 1.0f,
193 std::min(middleValue - minBand / 2,
194 scale.PositionToValue(xmin)
195 ));
196 max = std::min(halfrate,
197 std::max(middleValue + minBand / 2,
198 scale.PositionToValue(xmax)
199 ));
200 }
201 break;
202 case kZoomIn:
203 {
204 // Center the zoom-in at the click
205 const float p1 = (zoomStart - ypos) / (float)height;
206 const float middle = 1.0f - p1;
207 const float middleValue = scale.PositionToValue(middle);
208
209 if (fixedMousePoint) {
210 min = std::max(spectrumLinear ? 0.0f : 1.0f,
211 std::min(middleValue - minBand * middle,
212 scale.PositionToValue(0.5f * middle)
213 ));
214 max = std::min(halfrate,
215 std::max(middleValue + minBand * p1,
216 scale.PositionToValue(middle + 0.5f * p1)
217 ));
218 }
219 else {
220 min = std::max(spectrumLinear ? 0.0f : 1.0f,
221 std::min(middleValue - minBand / 2,
222 scale.PositionToValue(middle - 0.25f)
223 ));
224 max = std::min(halfrate,
225 std::max(middleValue + minBand / 2,
226 scale.PositionToValue(middle + 0.25f)
227 ));
228 }
229 }
230 break;
231 case kZoomOut:
232 {
233 // Zoom out
234 const float p1 = (zoomStart - ypos) / (float)height;
235 // (Used to zoom out centered at midline, ignoring the click, if linear view.
236 // I think it is better to be consistent. PRL)
237 // Center zoom-out at the midline
238 const float middle = // spectrumLinear ? 0.5f :
239 1.0f - p1;
240
241 if (fixedMousePoint) {
242 min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle));
243 max = std::min(halfrate, scale.PositionToValue(1.0f + p1));
244 }
245 else {
246 min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
247 max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
248 }
249 }
250 break;
251 }
252
253 // Now actually apply the zoom.
254 for (auto channel : TrackList::Channels(pTrack))
255 channel->SetSpectrumBounds(min, max);
256
257 zoomEnd = zoomStart = 0;
258 if( pProject )
259 ProjectHistory::Get( *pProject ).ModifyState(true);
260}
261
263// Table class
264
266{
267 static SpectrumVRulerMenuTable instance;
268 return instance;
269}
270
272
273BeginSection( "Scales" );
274 {
276 for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
278 OnFirstSpectrumScaleID + ii, names[ii].Msgid(),
279 POPUP_MENU_FN( OnSpectrumScaleType ),
280 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
281 WaveTrack *const wt =
282 static_cast<SpectrumVRulerMenuTable&>( handler )
283 .mpData->pTrack;
284 if ( id ==
286 (int)(wt->GetSpectrogramSettings().scaleType ) )
287 menu.Check(id, true);
288 }
289 );
290 }
291 }
293
294
295BeginSection( "Zoom" );
296 // Accelerators only if zooming enabled.
297 bool bVZoom;
298 gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false);
299
300 AppendItem( "Reset", OnZoomResetID, XXO("Zoom Reset"),
301 POPUP_MENU_FN( OnZoomReset ) );
303 MakeLabel( XXO("Zoom to Fit"), bVZoom, XXO("Shift-Right-Click") ),
304 POPUP_MENU_FN( OnZoomFitVertical ) );
306 MakeLabel( XXO("Zoom In"), bVZoom, XXO("Left-Click/Left-Drag") ),
307 POPUP_MENU_FN( OnZoomInVertical ) );
309 MakeLabel( XXO("Zoom Out"), bVZoom, XXO("Shift-Left-Click") ),
310 POPUP_MENU_FN( OnZoomOutVertical ) );
311EndSection();
312
314
315void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
316{
317 WaveTrack *const wt = mpData->pTrack;
318
319 const SpectrogramSettings::ScaleType newScaleType =
321 std::max(0,
323 evt.GetId() - OnFirstSpectrumScaleID
324 )));
325 if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
326 for (auto channel : TrackList::Channels(wt))
327 channel->GetIndependentSpectrogramSettings().scaleType = newScaleType;
328
329 ProjectHistory::Get( mpData->project ).ModifyState(true);
330
331 using namespace RefreshCode;
332 mpData->result = UpdateVRuler | RefreshAll;
333 }
334}
wxT("CloseDown"))
@ Internal
Indicates internal failure from Audacity.
int min(int a, int b)
#define XXO(s)
Definition: Internat.h:44
@ OnZoomOutVerticalID
@ OnZoomFitVerticalID
@ OnZoomInVerticalID
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
FileConfig * gPrefs
Definition: Prefs.cpp:71
IntSetting SpectrumMaxFreq
EndSection()
bool bVZoom
AppendItem("Reset", OnZoomResetID, XXO("Zoom Reset"), POPUP_MENU_FN(OnZoomReset))
BeginSection("Scales")
static TranslatableStrings names
Definition: TagsEditor.cpp:151
@ OnFirstSpectrumScaleID
AppendRadioItem("Instrument1", OnInstrument1ID, GetWaveColorStr(0), POPUP_MENU_FN(OnWaveColorChange), fn)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
float PositionToValue(float pp) const
Definition: NumberScale.h:154
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:200
Spectrogram settings, either for one track or as defaults.
NumberScale GetScale(float minFreq, float maxFreq) const
static const EnumValueSymbols & GetScaleNames()
static PopupMenuTable & Instance()
static void DoZoom(AudacityProject *pProject, WaveTrack *pTrack, WaveTrackViewConstants::ZoomActions ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint)
std::weak_ptr< WaveTrack > mpTrack
SpectrumVZoomHandle(const SpectrumVZoomHandle &)
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
void Enter(bool forward, AudacityProject *) override
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
~SpectrumVZoomHandle() override
Result Cancel(AudacityProject *pProject) override
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1603
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:486
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1541
Result mChangeHighlight
Definition: UIHandle.h:139
unsigned Result
Definition: UIHandle.h:38
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:799
double GetRate() const override
Definition: WaveTrack.cpp:479
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:352
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
AUDACITY_DLL_API HitTestPreview HitPreview(const wxMouseState &state)
AUDACITY_DLL_API void DoDraw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass, int zoomStart, int zoomEnd)
AUDACITY_DLL_API Result DoRelease(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent, WaveTrack *pTrack, const wxRect &mRect, DoZoomFunction doZoom, PopupMenuTable &table, int zoomStart, int zoomEnd)
AUDACITY_DLL_API wxRect DoDrawingArea(const wxRect &rect, const wxRect &panelRect, unsigned iPass)
AUDACITY_DLL_API bool IsDragZooming(int zoomStart, int zoomEnd)
AUDACITY_DLL_API Result DoDrag(const TrackPanelMouseEvent &event, AudacityProject *pProject, int zoomStart, int &zoomEnd)
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:753