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 WaveChannelVZoomHandle.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<WaveChannel> &pChannel, const wxRect &rect, int y
27) : mpChannel{ pChannel }, mZoomStart(y), mZoomEnd(y), mRect(rect)
28{
29}
30
32
33std::shared_ptr<const Track> SpectrumVZoomHandle::FindTrack() const
34{
35 return TrackFromChannel(mpChannel.lock());
36}
37
38std::shared_ptr<WaveChannel> SpectrumVZoomHandle::FindWaveChannel()
39{
40 return mpChannel.lock();
41}
42
44{
45#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
47#endif
48}
49
51{
52 return true;
53}
54
57{
59}
60
62 const TrackPanelMouseEvent &evt, AudacityProject *pProject)
63{
64 using namespace RefreshCode;
65 if (!FindTrack())
66 return Cancelled;
67 return WaveChannelVZoomHandle::DoDrag(evt, pProject, mZoomStart, mZoomEnd, true);
68}
69
72{
74}
75
77 const TrackPanelMouseEvent &evt, AudacityProject *pProject,
78 wxWindow *pParent)
79{
80 const auto pChannel = FindWaveChannel();
81 if (!pChannel)
84 evt, pProject, pParent, *pChannel, mRect,
87}
88
90{
91 // Cancel is implemented! And there is no initial state to restore,
92 // so just return a code.
94}
95
98 const wxRect &rect, unsigned iPass )
99{
100 const auto pChannel = FindTrack();
101 if (!pChannel)
102 return;
104 context, rect, iPass, mZoomStart, mZoomEnd, true );
105}
106
109 const wxRect &rect, const wxRect &panelRect, unsigned iPass )
110{
111 return WaveChannelVZoomHandle::DoDrawingArea(rect, panelRect, iPass);
112}
113
114// ZoomKind says how to zoom.
115// If ZoomStart and ZoomEnd are not equal, this may override
116// the zoomKind and cause a drag-zoom-in.
118 AudacityProject *pProject,
119 WaveChannel &wc,
121 const wxRect &rect, int zoomStart, int zoomEnd,
122 bool fixedMousePoint)
123{
124 using namespace WaveChannelViewConstants;
125 static const float ZOOMLIMIT = 0.001f;
126
127 int height = rect.height;
128 int ypos = rect.y;
129
130 // Ensure start and end are in order (swap if not).
131 if (zoomEnd < zoomStart)
132 std::swap( zoomStart, zoomEnd );
133
134 float min, max, minBand = 0;
135 const double rate = wc.GetRate();
136 const float halfrate = rate / 2;
137 float maxFreq = 8000.0;
138 const auto &specSettings = SpectrogramSettings::Get(wc);
139 NumberScale scale;
140 const bool spectrumLinear =
141 (specSettings.scaleType == SpectrogramSettings::stLinear);
142 auto &bounds = SpectrogramBounds::Get(wc);
143
144 bool bDragZoom = WaveChannelVZoomHandle::IsDragZooming(zoomStart, zoomEnd, true);
145 // Add 100 if spectral to separate the kinds of zoom.
146 const int kSpectral = 100;
147
148 // Possibly override the zoom kind.
149 if( bDragZoom )
150 ZoomKind = kZoomInByDrag;
151
152 float top=2.0;
153 float half=0.5;
154
155 {
156 bounds.GetBounds(wc, min, max);
157 scale = (specSettings.GetScale(min, max));
158 const auto fftLength = specSettings.GetFFTLength();
159 const float binSize = rate / fftLength;
160 maxFreq = SpectrumMaxFreq.Read();
161 // JKC: Following discussions of Bug 1208 I'm allowing zooming in
162 // down to one bin.
163 // const int minBins =
164 // std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
165 const int minBins = 1;
166 minBand = minBins * binSize;
167 }
168
169 // Compute min and max.
170 switch(ZoomKind)
171 {
172 default:
173 // If we have covered all the cases, this won't happen.
174 // In release builds Audacity will ignore the zoom.
175 wxFAIL_MSG("Zooming Case not implemented by Audacity");
176 break;
177
178 // VZooming on spectral we don't implement the other zoom presets.
179 // They are also not in the menu.
180 case kZoomReset:
181 {
182 // Zoom out to normal level.
183 min = spectrumLinear ? 0.0f : 1.0f;
184 max = maxFreq;
185 }
186 break;
187 case kZoom1to1:
188 case kZoomHalfWave:
189 {
190 // Zoom out full
191 min = spectrumLinear ? 0.0f : 1.0f;
192 max = halfrate;
193 }
194 break;
195 case kZoomInByDrag:
196 {
197 double xmin = 1 - (zoomEnd - ypos) / (float)height;
198 double xmax = 1 - (zoomStart - ypos) / (float)height;
199 const float middle = (xmin + xmax) / 2;
200 const float middleValue = scale.PositionToValue(middle);
201
202 min = std::max(spectrumLinear ? 0.0f : 1.0f,
203 std::min(middleValue - minBand / 2,
204 scale.PositionToValue(xmin)
205 ));
206 max = std::min(halfrate,
207 std::max(middleValue + minBand / 2,
208 scale.PositionToValue(xmax)
209 ));
210 }
211 break;
212 case kZoomIn:
213 {
214 // Center the zoom-in at the click
215 const float p1 = (zoomStart - ypos) / (float)height;
216 const float middle = 1.0f - p1;
217 const float middleValue = scale.PositionToValue(middle);
218
219 if (fixedMousePoint) {
220 min = std::max(spectrumLinear ? 0.0f : 1.0f,
221 std::min(middleValue - minBand * middle,
222 scale.PositionToValue(0.5f * middle)
223 ));
224 max = std::min(halfrate,
225 std::max(middleValue + minBand * p1,
226 scale.PositionToValue(middle + 0.5f * p1)
227 ));
228 }
229 else {
230 min = std::max(spectrumLinear ? 0.0f : 1.0f,
231 std::min(middleValue - minBand / 2,
232 scale.PositionToValue(middle - 0.25f)
233 ));
234 max = std::min(halfrate,
235 std::max(middleValue + minBand / 2,
236 scale.PositionToValue(middle + 0.25f)
237 ));
238 }
239 }
240 break;
241 case kZoomOut:
242 {
243 // Zoom out
244 const float p1 = (zoomStart - ypos) / (float)height;
245 // (Used to zoom out centered at midline, ignoring the click, if linear view.
246 // I think it is better to be consistent. PRL)
247 // Center zoom-out at the midline
248 const float middle = // spectrumLinear ? 0.5f :
249 1.0f - p1;
250
251 if (fixedMousePoint) {
252 min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle));
253 max = std::min(halfrate, scale.PositionToValue(1.0f + p1));
254 }
255 else {
256 min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
257 max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
258 }
259 }
260 break;
261 }
262
263 // Now actually apply the zoom.
264 bounds.SetBounds(min, max);
265
266 zoomEnd = zoomStart = 0;
267 if( pProject )
268 ProjectHistory::Get( *pProject ).ModifyState(true);
269}
270
272// Table class
273
275{
276 static SpectrumVRulerMenuTable instance;
277 return instance;
278}
279
281 //Generate scales (Mel, Logarithmic, etc)
282 const auto & names = SpectrogramSettings::GetScaleNames();
283 for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
285 OnFirstSpectrumScaleID + ii, names[ii].Msgid(),
286 POPUP_MENU_FN( OnSpectrumScaleType ),
287 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
288 auto &wc =
289 static_cast<SpectrumVRulerMenuTable&>(handler)
290 .mpData->wc;
291 if ( id ==
293 static_cast<int>(SpectrogramSettings::Get(wc).scaleType))
294 menu.Check(id, true);
295 }
296 );
297 }
298
299
300BeginSection( "Zoom" );
301 AppendItem( "In", OnZoomInVerticalID, XXO("Zoom In"),POPUP_MENU_FN( OnZoomInVertical ) );
302 AppendItem( "Out", OnZoomOutVerticalID, XXO("Zoom Out"), POPUP_MENU_FN( OnZoomOutVertical ) );
303 AppendItem( "Fit", OnZoomFitVerticalID, XXO("Zoom to Fit"), POPUP_MENU_FN( OnZoomFitVertical ) );
304 AppendItem( "Reset", OnZoomResetID, XXO("Reset Zoom"),POPUP_MENU_FN( OnZoomReset ) );
306
308
309void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
310{
311 auto &wc = mpData->wc;
312 const SpectrogramSettings::ScaleType newScaleType =
314 std::max(0,
316 evt.GetId() - OnFirstSpectrumScaleID
317 )));
318 if (SpectrogramSettings::Get(wc).scaleType != newScaleType) {
319 SpectrogramSettings::Own(wc).scaleType = newScaleType;
320
321 ProjectHistory::Get( mpData->project ).ModifyState(true);
322
323 using namespace RefreshCode;
324 mpData->result = UpdateVRuler | RefreshAll;
325 }
326}
@ Internal
Indicates internal failure from Audacity.
int min(int a, int b)
XXO("&Cut/Copy/Paste Toolbar")
@ OnZoomOutVerticalID
@ OnZoomFitVerticalID
@ OnZoomInVerticalID
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
IntSetting SpectrumMaxFreq
EndSection()
BeginSection("Zoom")
for(int ii=0, nn=names.size();ii< nn;++ii)
AppendItem("In", OnZoomInVerticalID, XXO("Zoom In"), POPUP_MENU_FN(OnZoomInVertical))
const auto & names
@ 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:90
float PositionToValue(float pp) const
Definition: NumberScale.h:155
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:207
static SpectrogramBounds & Get(WaveTrack &track)
Get either the global default settings, or the track's own if previously created.
Spectrogram settings, either for one track or as defaults.
static SpectrogramSettings & Get(const WaveTrack &track)
static SpectrogramSettings & Own(WaveChannel &wc)
static PopupMenuTable & Instance()
static void DoZoom(AudacityProject *pProject, WaveChannel &wc, WaveChannelViewConstants::ZoomActions ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint)
SpectrumVZoomHandle(const SpectrumVZoomHandle &)
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
std::shared_ptr< WaveChannel > FindWaveChannel()
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
std::shared_ptr< const Track > FindTrack() const override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
std::weak_ptr< WaveChannel > mpChannel
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
static std::shared_ptr< const Track > TrackFromChannel(const std::shared_ptr< const Channel > &pChannel)
A frequent convenience in the definition of UIHandles.
Definition: UIHandle.cpp:63
Result mChangeHighlight
Definition: UIHandle.h:152
unsigned Result
Definition: UIHandle.h:40
double GetRate() const override
Definition: WaveTrack.cpp:793
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
AUDACITY_DLL_API Result DoRelease(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent, WaveChannel &wc, const wxRect &mRect, DoZoomFunction doZoom, PopupMenuTable &table, int zoomStart, int zoomEnd)
AUDACITY_DLL_API bool IsDragZooming(int zoomStart, int zoomEnd, bool hasDragZoom)
AUDACITY_DLL_API HitTestPreview HitPreview(const bool bVZoom)
AUDACITY_DLL_API void DoDraw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass, int zoomStart, int zoomEnd, bool hasDragZoom)
AUDACITY_DLL_API wxRect DoDrawingArea(const wxRect &rect, const wxRect &panelRect, unsigned iPass)
AUDACITY_DLL_API Result DoDrag(const TrackPanelMouseEvent &event, AudacityProject *pProject, int zoomStart, int &zoomEnd, bool hasDragZoom)
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:628