Audacity  2.2.2
TimeTrack.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  TimeTrack.cpp
6 
7  Dr William Bland
8 
9 *******************************************************************//*******************************************************************/
15 
16 #include "Audacity.h"
17 #include "TimeTrack.h"
18 #include "Experimental.h"
19 
20 #include <cfloat>
21 #include <wx/intl.h>
22 #include "AColor.h"
23 #include "widgets/Ruler.h"
24 #include "Envelope.h"
25 #include "Prefs.h"
26 #include "Project.h"
27 #include "Internat.h"
28 #include "ViewInfo.h"
29 #include "AllThemeResources.h"
30 
31 //TODO-MB: are these sensible values?
32 #define TIMETRACK_MIN 0.01
33 #define TIMETRACK_MAX 10.0
34 
35 std::unique_ptr<TimeTrack> TrackFactory::NewTimeTrack()
36 {
37  return std::make_unique<TimeTrack>(mDirManager, mZoomInfo);
38 }
39 
40 TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const ZoomInfo *zoomInfo):
41  Track(projDirManager)
42  , mZoomInfo(zoomInfo)
43 {
44  mHeight = 100;
45 
46  mRangeLower = 0.9;
47  mRangeUpper = 1.1;
48  mDisplayLog = false;
49 
50  mEnvelope = std::make_unique<Envelope>(true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
51  mEnvelope->SetTrackLen(DBL_MAX);
52  mEnvelope->SetOffset(0);
53 
54  SetDefaultName(_("Time Track"));
56 
57  mRuler = std::make_unique<Ruler>();
58  mRuler->SetUseZoomInfo(0, mZoomInfo);
59  mRuler->SetLabelEdges(false);
60  mRuler->SetFormat(Ruler::TimeFormat);
61 }
62 
63 TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1)
64  : Track(orig)
65  , mZoomInfo(orig.mZoomInfo)
66 {
67  Init(orig); // this copies the TimeTrack metadata (name, range, etc)
68 
69  auto len = DBL_MAX;
70  if (pT0 && pT1) {
71  len = *pT1 - *pT0;
72  mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope, *pT0, *pT1 );
73  }
74  else
75  mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope );
76  mEnvelope->SetTrackLen( len );
77  mEnvelope->SetOffset(0);
78 
80  mRuler = std::make_unique<Ruler>();
81  mRuler->SetUseZoomInfo(0, mZoomInfo);
82  mRuler->SetLabelEdges(false);
83  mRuler->SetFormat(Ruler::TimeFormat);
84 }
85 
86 // Copy the track metadata but not the contents.
87 void TimeTrack::Init(const TimeTrack &orig)
88 {
89  Track::Init(orig);
91  SetName(orig.GetName());
95 }
96 
98 {
99 }
100 
101 Track::Holder TimeTrack::Cut( double t0, double t1 )
102 {
103  auto result = Copy( t0, t1, false );
104  Clear( t0, t1 );
105  return result;
106 }
107 
108 Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const
109 {
110  auto result = std::make_unique<TimeTrack>( *this, &t0, &t1 );
111  return Track::Holder{ std::move( result ) };
112 }
113 
114 void TimeTrack::Clear(double t0, double t1)
115 {
116  auto sampleTime = 1.0 / GetActiveProject()->GetRate();
117  mEnvelope->CollapseRegion( t0, t1, sampleTime );
118 }
119 
120 void TimeTrack::Paste(double t, const Track * src)
121 {
122  if (src->GetKind() != Track::Time)
123  // THROW_INCONSISTENCY_EXCEPTION; // ?
124  return;
125 
126  auto sampleTime = 1.0 / GetActiveProject()->GetRate();
127  mEnvelope->Paste
128  (t, static_cast<const TimeTrack*>(src)->mEnvelope.get(), sampleTime);
129 }
130 
131 void TimeTrack::Silence(double WXUNUSED(t0), double WXUNUSED(t1))
132 {
133 }
134 
135 void TimeTrack::InsertSilence(double t, double len)
136 {
137  mEnvelope->InsertSpace(t, len);
138 }
139 
141 {
142  return std::make_unique<TimeTrack>(*this);
143 }
144 
146 {
147  return mEnvelope->GetExponential();
148 }
149 
150 void TimeTrack::SetInterpolateLog(bool interpolateLog) {
151  mEnvelope->SetExponential(interpolateLog);
152 }
153 
154 //Compute the (average) warp factor between two non-warped time points
155 double TimeTrack::ComputeWarpFactor(double t0, double t1) const
156 {
157  return GetEnvelope()->AverageOfInverse(t0, t1);
158 }
159 
160 double TimeTrack::ComputeWarpedLength(double t0, double t1) const
161 {
162  return GetEnvelope()->IntegralOfInverse(t0, t1);
163 }
164 
165 double TimeTrack::SolveWarpedLength(double t0, double length) const
166 {
167  return GetEnvelope()->SolveIntegralOfInverse(t0, length);
168 }
169 
170 bool TimeTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
171 {
172  if (!wxStrcmp(tag, wxT("timetrack"))) {
173  mRescaleXMLValues = true; // will be set to false if upper/lower is found
174  long nValue;
175  while(*attrs) {
176  const wxChar *attr = *attrs++;
177  const wxChar *value = *attrs++;
178 
179  if (!value)
180  break;
181 
182  const wxString strValue = value;
183  if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue))
184  mName = strValue;
185  else if (!wxStrcmp(attr, wxT("height")) &&
186  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
187  mHeight = nValue;
188  else if (!wxStrcmp(attr, wxT("minimized")) &&
189  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
190  mMinimized = (nValue != 0);
191  else if (!wxStrcmp(attr, wxT("rangelower")))
192  {
194  mRescaleXMLValues = false;
195  }
196  else if (!wxStrcmp(attr, wxT("rangeupper")))
197  {
199  mRescaleXMLValues = false;
200  }
201  else if (!wxStrcmp(attr, wxT("displaylog")) &&
202  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
203  {
204  SetDisplayLog(nValue != 0);
205  //TODO-MB: This causes a graphical glitch, TrackPanel should probably be Refresh()ed after loading.
206  // I don't know where to do this though.
207  }
208  else if (!wxStrcmp(attr, wxT("interpolatelog")) &&
209  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
210  {
211  SetInterpolateLog(nValue != 0);
212  }
213 
214  } // while
216  mEnvelope->SetRange(0.0, 1.0); // this will be restored to the actual range later
217  return true;
218  }
219 
220  return false;
221 }
222 
223 void TimeTrack::HandleXMLEndTag(const wxChar * WXUNUSED(tag))
224 {
226  {
227  mRescaleXMLValues = false;
228  mEnvelope->RescaleValues(mRangeLower, mRangeUpper);
230  }
231 }
232 
234 {
235  if (!wxStrcmp(tag, wxT("envelope")))
236  return mEnvelope.get();
237 
238  return NULL;
239 }
240 
241 void TimeTrack::WriteXML(XMLWriter &xmlFile) const
242 // may throw
243 {
244  xmlFile.StartTag(wxT("timetrack"));
245 
246  xmlFile.WriteAttr(wxT("name"), mName);
247  //xmlFile.WriteAttr(wxT("channel"), mChannel);
248  //xmlFile.WriteAttr(wxT("offset"), mOffset, 8);
249  xmlFile.WriteAttr(wxT("height"), GetActualHeight());
250  xmlFile.WriteAttr(wxT("minimized"), GetMinimized());
251  xmlFile.WriteAttr(wxT("rangelower"), mRangeLower, 12);
252  xmlFile.WriteAttr(wxT("rangeupper"), mRangeUpper, 12);
253  xmlFile.WriteAttr(wxT("displaylog"), GetDisplayLog());
254  xmlFile.WriteAttr(wxT("interpolatelog"), GetInterpolateLog());
255 
256  mEnvelope->WriteXML(xmlFile);
257 
258  xmlFile.EndTag(wxT("timetrack"));
259 }
260 
263 
264 void TimeTrack::Draw
265 (TrackPanelDrawingContext &context, const wxRect & r, const ZoomInfo &zoomInfo) const
266 {
267  auto &dc = context.dc;
268  bool highlight = false;
269 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
270  auto target = dynamic_cast<EnvelopeHandle*>(context.target.get());
271  highlight = target && target->GetEnvelope() == this->GetEnvelope();
272 #endif
273 
274  double min = zoomInfo.PositionToTime(0);
275  double max = zoomInfo.PositionToTime(r.width);
276  if (min > max)
277  {
278  wxASSERT(false);
279  min = max;
280  }
281 
282  AColor::UseThemeColour( &dc, clrUnselected );
283  dc.DrawRectangle(r);
284 
285  //copy this rectangle away for future use.
286  wxRect mid = r;
287 
288  // Draw the Ruler
289  mRuler->SetBounds(r.x, r.y, r.x + r.width - 1, r.y + r.height - 1);
290  mRuler->SetRange(min, max);
291  mRuler->SetFlip(false); // If we don't do this, the Ruler doesn't redraw itself when the envelope is modified.
292  // I have no idea why!
293  //
294  // LL: It's because the ruler only Invalidate()s when the NEW value is different
295  // than the current value.
296  mRuler->SetFlip(GetHeight() > 75 ? true : true); // MB: so why don't we just call Invalidate()? :)
297  mRuler->SetTickColour( theTheme.Colour( clrTrackPanelText ));
298  mRuler->Draw(dc, this);
299 
300  Doubles envValues{ size_t(mid.width) };
301  GetEnvelope()->GetValues
302  ( 0, 0, envValues.get(), mid.width, 0, zoomInfo );
303 
304  wxPen &pen = highlight ? AColor::uglyPen : AColor::envelopePen;
305  dc.SetPen( pen );
306 
307  double logLower = log(std::max(1.0e-7, mRangeLower)), logUpper = log(std::max(1.0e-7, mRangeUpper));
308  for (int x = 0; x < mid.width; x++)
309  {
310  double y;
311  if(mDisplayLog)
312  y = (double)mid.height * (logUpper - log(envValues[x])) / (logUpper - logLower);
313  else
314  y = (double)mid.height * (mRangeUpper - envValues[x]) / (mRangeUpper - mRangeLower);
315  int thisy = r.y + (int)y;
316  AColor::Line(dc, mid.x + x, thisy - 1, mid.x + x, thisy+2);
317  }
318 }
319 
321 {
322  GetEnvelope()->Flatten(0.0);
323  GetEnvelope()->InsertOrReplace(0.0, 0.2);
324  GetEnvelope()->InsertOrReplace(5.0 - 0.001, 0.2);
325  GetEnvelope()->InsertOrReplace(5.0 + 0.001, 1.3);
326  GetEnvelope()->InsertOrReplace(10.0, 1.3);
327 
328  double value1 = GetEnvelope()->Integral(2.0, 13.0);
329  double expected1 = (5.0 - 2.0) * 0.2 + (13.0 - 5.0) * 1.3;
330  double value2 = GetEnvelope()->IntegralOfInverse(2.0, 13.0);
331  double expected2 = (5.0 - 2.0) / 0.2 + (13.0 - 5.0) / 1.3;
332  if( fabs(value1 - expected1) > 0.01 )
333  {
334  wxPrintf( "TimeTrack: Integral failed! expected %f got %f\n", expected1, value1);
335  }
336  if( fabs(value2 - expected2) > 0.01 )
337  {
338  wxPrintf( "TimeTrack: IntegralOfInverse failed! expected %f got %f\n", expected2, value2);
339  }
340 
341  /*double reqt0 = 10.0 - .1;
342  double reqt1 = 10.0 + .1;
343  double t0 = warp( reqt0 );
344  double t1 = warp( reqt1 );
345  if( t0 > t1 )
346  {
347  wxPrintf( "TimeTrack: Warping reverses an interval! [%.2f,%.2f] -> [%.2f,%.2f]\n",
348  reqt0, reqt1,
349  t0, t1 );
350  }*/
351 }
352 
bool GetDisplayLog() const
Definition: TimeTrack.h:133
void Init(const TimeTrack &orig)
Copy the metadata from another track but not the points.
Definition: TimeTrack.cpp:87
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
double ComputeWarpedLength(double t0, double t1) const
Compute the duration (in seconds at playback) of the specified region of the track.
Definition: TimeTrack.cpp:160
void SetRangeUpper(double upper)
Definition: TimeTrack.h:131
void Silence(double t0, double t1) override
Definition: TimeTrack.cpp:131
double AverageOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1408
void Flatten(double value)
Definition: Envelope.cpp:137
#define TIMETRACK_MAX
Definition: TimeTrack.cpp:33
int mHeight
Definition: Track.h:117
void InsertSilence(double t, double len) override
Definition: TimeTrack.cpp:135
double GetRangeLower() const
Definition: TimeTrack.h:127
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ViewInfo.cpp:49
double SolveIntegralOfInverse(double t0, double area) const
Definition: Envelope.cpp:1625
void SetDisplayLog(bool displayLog)
Definition: TimeTrack.h:134
const std::shared_ptr< DirManager > mDirManager
Definition: Track.h:871
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
Definition: TimeTrack.cpp:233
bool GetInterpolateLog() const
Definition: TimeTrack.cpp:145
bool mDisplayLog
Definition: TimeTrack.h:146
static wxPen uglyPen
Definition: AColor.h:147
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
virtual int GetKind() const
Definition: Track.h:329
void Paste(double t, const Track *src) override
Definition: TimeTrack.cpp:120
wxString GetDefaultName() const
Definition: Track.h:272
const ZoomInfo *const mZoomInfo
Definition: TimeTrack.h:141
static wxPen envelopePen
Definition: AColor.h:122
double mRangeUpper
Definition: TimeTrack.h:145
void Draw(TrackPanelDrawingContext &context, const wxRect &r, const ZoomInfo &zoomInfo) const
Definition: TimeTrack.cpp:265
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override
Definition: TimeTrack.cpp:170
std::unique_ptr< TimeTrack > NewTimeTrack()
Definition: TimeTrack.cpp:35
void Clear(double t0, double t1) override
Definition: TimeTrack.cpp:114
double GetRangeUpper() const
Definition: TimeTrack.h:128
void testMe()
Definition: TimeTrack.cpp:320
static bool IsGoodString(const wxString &str)
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:122
int InsertOrReplace(double when, double value)
Add a point at a particular absolute time coordinate.
Definition: Envelope.h:194
double IntegralOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1562
bool mMinimized
Definition: Track.h:124
#define TIMETRACK_MIN
Definition: TimeTrack.cpp:32
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:70
double mRangeLower
Definition: TimeTrack.h:144
int min(int a, int b)
wxString GetName() const
Definition: Track.h:270
TimeTrack(const std::shared_ptr< DirManager > &projDirManager, const ZoomInfo *zoomInfo)
Definition: TimeTrack.cpp:40
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1)
Definition: AColor.cpp:289
std::unique_ptr< Envelope > mEnvelope
Definition: TimeTrack.h:142
Holder Cut(double t0, double t1) override
Definition: TimeTrack.cpp:101
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
void SetDefaultName(const wxString &n)
Definition: Track.h:273
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
Holder Copy(double t0, double t1, bool forClipboard) const override
Definition: TimeTrack.cpp:108
void SetInterpolateLog(bool interpolateLog)
Definition: TimeTrack.cpp:150
void SetName(const wxString &n)
Definition: Track.h:271
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
Envelope * GetEnvelope() const
virtual ~TimeTrack()
Definition: TimeTrack.cpp:97
void Init(const Track &orig)
Definition: Track.cpp:83
std::unique_ptr< Ruler > mRuler
Definition: TimeTrack.h:143
Track::Holder Duplicate() const override
Definition: TimeTrack.cpp:140
const ZoomInfo *const mZoomInfo
Definition: Track.h:872
double SolveWarpedLength(double t0, double length) const
Compute how much unwarped time must have elapsed if length seconds of warped time has elapsed...
Definition: TimeTrack.cpp:165
bool mRescaleXMLValues
Definition: TimeTrack.h:147
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
double GetRate() const
Definition: Project.h:199
Envelope * GetEnvelope()
Definition: TimeTrack.h:90
std::unique_ptr< Track > Holder
Definition: Track.h:263
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:22
void SetRangeLower(double lower)
Definition: TimeTrack.h:130
double ComputeWarpFactor(double t0, double t1) const
Compute the integral warp factor between two non-warped time points.
Definition: TimeTrack.cpp:155
void HandleXMLEndTag(const wxChar *tag) override
Definition: TimeTrack.cpp:223
void WriteXML(XMLWriter &xmlFile) const override
Definition: TimeTrack.cpp:241
double Integral(double t0, double t1) const
Definition: Envelope.cpp:1499
wxString mName
Definition: Track.h:118