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