Labeller.h
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006-2007 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #ifndef SV_LABELLER_H
17 #define SV_LABELLER_H
18 
19 #include "base/Selection.h"
20 #include "base/Event.h"
21 
22 #include "EventCommands.h"
23 
24 #include <QObject>
25 
26 #include <map>
27 #include <iostream>
28 
29 class Labeller : public QObject
30 {
31  Q_OBJECT
32 
33 public:
34  enum ValueType {
47  };
48 
49  // uses:
50  //
51  // 1. when adding points to a time-value model, generate values
52  // for those points based on their times or labels or a counter
53  //
54  // 2. when adding a single point to a time-instant model, generate
55  // a label for it based on its time and that of the previous point
56  // or a counter
57  //
58  // 3. when adding a single point to a time-instant model, generate
59  // a label for the previous point based on its time and that of
60  // the point just added (as tempo is based on time to the next
61  // point, not the previous one)
62  //
63  // 4. re-label a set of points that have already been added to a
64  // model
65  //
66  // 5. generate new labelled points in the gaps between other
67  // points (subdivide), or remove them (winnow)
68 
70  m_type(type),
71  m_counter(1),
72  m_counter2(1),
73  m_cycle(4),
74  m_dp(10),
75  m_rate(0) { }
76 
77  Labeller(const Labeller &l) :
78  QObject(),
79  m_type(l.m_type),
82  m_cycle(l.m_cycle),
83  m_dp(l.m_dp),
84  m_rate(l.m_rate) { }
85 
86  virtual ~Labeller() { }
87 
88  typedef std::map<ValueType, QString> TypeNameMap;
89  TypeNameMap getTypeNames() const {
90  TypeNameMap m;
91  m[ValueNone]
92  = tr("No numbering");
94  = tr("Simple counter");
96  = tr("Cyclical counter");
98  = tr("Cyclical two-level counter (bar/beat)");
100  = tr("Audio sample frame number");
102  = tr("Time in seconds");
104  = tr("Duration to the following item");
106  = tr("Tempo (bpm) based on duration to following item");
108  = tr("Duration since the previous item");
110  = tr("Tempo (bpm) based on duration since previous item");
112  = tr("Same as the nearest previous item");
113  m[ValueFromLabel]
114  = tr("Value extracted from the item's label (where possible)");
115  return m;
116  }
117 
118  ValueType getType() const { return m_type; }
119  void setType(ValueType type) { m_type = type; }
120 
121  int getCounterValue() const { return m_counter; }
122  void setCounterValue(int v) { m_counter = v; }
123 
124  int getSecondLevelCounterValue() const { return m_counter2; }
126 
127  int getCounterCycleSize() const { return m_cycle; }
128  void setCounterCycleSize(int s) {
129  m_cycle = s;
130  m_dp = 1;
131  while (s > 0) {
132  s /= 10;
133  m_dp *= 10;
134  }
135  if (m_counter > m_cycle) m_counter = 1;
136  }
137 
138  void setSampleRate(sv_samplerate_t rate) { m_rate = rate; }
139 
140  void resetCounters() {
141  m_counter = 1;
142  m_counter2 = 1;
143  m_cycle = 4;
144  }
145 
147  m_counter++;
150  if (m_counter > m_cycle) {
151  m_counter = 1;
152  m_counter2++;
153  }
154  }
155  }
156 
157  enum Application {
160  };
161  typedef std::pair<Application, Event> Relabelling;
162  typedef std::pair<Application, Event> Revaluing;
163 
170  Relabelling
171  label(Event e, const Event *prev = nullptr) {
172 
173  QString label = e.getLabel();
174 
175  if (m_type == ValueNone) {
176  label = "";
177  } else if (m_type == ValueFromTwoLevelCounter) {
178  label = tr("%1.%2").arg(m_counter2).arg(m_counter);
180  } else if (m_type == ValueFromFrameNumber) {
181  // avoid going through floating-point value
182  label = tr("%1").arg(e.getFrame());
183  } else {
184  float value = getValueFor(e, prev);
185  label = QString("%1").arg(value);
186  }
187 
188  if (actingOnPrevEvent() && prev) {
189  return { AppliesToPreviousEvent, prev->withLabel(label) };
190  } else {
191  return { AppliesToThisEvent, e.withLabel(label) };
192  }
193  }
194 
202  Revaluing
203  revalue(Event e, const Event *prev = nullptr) {
204 
205  float value = e.getValue();
206 
208  if (!prev) {
209  std::cerr << "ERROR: Labeller::setValue: Previous point required but not provided" << std::endl;
210  } else {
211  return { AppliesToThisEvent, e.withValue(prev->getValue()) };
212  }
213  } else {
214  value = getValueFor(e, prev);
215  }
216 
217  if (actingOnPrevEvent() && prev) {
218  return { AppliesToPreviousEvent, prev->withValue(value) };
219  } else {
220  return { AppliesToThisEvent, e.withValue(value) };
221  }
222  }
223 
232  Command *labelAll(int editableId,
233  MultiSelection *ms,
234  const EventVector &allEvents) {
235 
236  auto command = new ChangeEventsCommand
237  (editableId, tr("Label Points"));
238 
239  Event prev;
240  bool havePrev = false;
241 
242  for (auto p: allEvents) {
243 
244  if (ms) {
245  Selection s(ms->getContainingSelection(p.getFrame(), false));
246  if (!s.contains(p.getFrame())) {
247  prev = p;
248  havePrev = true;
249  continue;
250  }
251  }
252 
253  auto labelling = label(p, havePrev ? &prev : nullptr);
254 
255  if (labelling.first == AppliesToThisEvent) {
256  command->remove(p);
257  } else {
258  command->remove(prev);
259  }
260 
261  command->add(labelling.second);
262 
263  prev = p;
264  havePrev = true;
265  }
266 
267  return command->finish();
268  }
269 
279  Command *subdivide(int editableId,
280  MultiSelection *ms,
281  const EventVector &allEvents,
282  int n) {
283 
284  auto command = new ChangeEventsCommand
285  (editableId, tr("Subdivide Points"));
286 
287  for (auto i = allEvents.begin(); i != allEvents.end(); ++i) {
288 
289  auto j = i;
290  // require a "next point" even if it's not in selection
291  if (++j == allEvents.end()) {
292  break;
293  }
294 
295  if (ms) {
296  Selection s(ms->getContainingSelection(i->getFrame(), false));
297  if (!s.contains(i->getFrame())) {
298  continue;
299  }
300  }
301 
302  Event p(*i);
303  Event nextP(*j);
304 
305  // n is the number of subdivisions, so we add n-1 new
306  // points equally spaced between p and nextP
307 
308  for (int m = 1; m < n; ++m) {
309  sv_frame_t f = p.getFrame() +
310  (m * (nextP.getFrame() - p.getFrame())) / n;
311  Event newPoint = p
312  .withFrame(f)
313  .withLabel(tr("%1.%2").arg(p.getLabel()).arg(m+1));
314  command->add(newPoint);
315  }
316  }
317 
318  return command->finish();
319  }
320 
330  Command *winnow(int editableId,
331  MultiSelection *ms,
332  const EventVector &allEvents,
333  int n) {
334 
335  auto command = new ChangeEventsCommand
336  (editableId, tr("Winnow Points"));
337 
338  int counter = 0;
339 
340  for (auto p: allEvents) {
341 
342  if (ms) {
343  Selection s(ms->getContainingSelection(p.getFrame(), false));
344  if (!s.contains(p.getFrame())) {
345  counter = 0;
346  continue;
347  }
348  }
349 
350  ++counter;
351 
352  if (counter == n+1) counter = 1;
353  if (counter == 1) {
354  // this is an Nth instant, don't remove it
355  continue;
356  }
357 
358  command->remove(p);
359  }
360 
361  return command->finish();
362  }
363 
364  bool requiresPrevPoint() const {
369  }
370 
371  bool actingOnPrevEvent() const {
372  return (m_type == ValueFromDurationToNext ||
374  }
375 
376 protected:
377  float getValueFor(Event p, const Event *prev) {
378 
379  float value = 0.f;
380 
381  switch (m_type) {
382 
383  case ValueNone:
384  value = 0;
385  break;
386 
389  value = float(m_counter);
391  break;
392 
394  value = float(m_counter2 + double(m_counter) / double(m_dp));
396  break;
397 
399  value = float(p.getFrame());
400  break;
401 
402  case ValueFromRealTime:
403  if (m_rate == 0.0) {
404  std::cerr << "ERROR: Labeller::getValueFor: Real-time conversion required, but no sample rate set" << std::endl;
405  } else {
406  value = float(double(p.getFrame()) / m_rate);
407  }
408  break;
409 
414  if (m_rate == 0.0) {
415  std::cerr << "ERROR: Labeller::getValueFor: Real-time conversion required, but no sample rate set" << std::endl;
416  } else if (!prev) {
417  std::cerr << "ERROR: Labeller::getValueFor: Time difference required, but only one point provided" << std::endl;
418  } else {
419  sv_frame_t f0 = prev->getFrame(), f1 = p.getFrame();
422  value = float(double(f1 - f0) / m_rate);
423  } else {
424  if (f1 > f0) {
425  value = float((60.0 * m_rate) / double(f1 - f0));
426  }
427  }
428  }
429  break;
430 
432  // need to deal with this in the calling function, as this
433  // function must handle points that don't have values to
434  // read from
435  break;
436 
437  case ValueFromLabel:
438  if (p.getLabel() != "") {
439  // more forgiving than QString::toFloat()
440  value = float(atof(p.getLabel().toLocal8Bit()));
441  } else {
442  value = 0.f;
443  }
444  break;
445  }
446 
447  return value;
448  }
449 
453  int m_cycle;
454  int m_dp;
456 };
457 
458 #endif
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
float getValueFor(Event p, const Event *prev)
Definition: Labeller.h:377
bool actingOnPrevEvent() const
Definition: Labeller.h:371
float getValue() const
Definition: Event.h:122
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
A selection object simply represents a range in time, via start and end frame.
Definition: Selection.h:40
bool requiresPrevPoint() const
Definition: Labeller.h:364
void setCounterCycleSize(int s)
Definition: Labeller.h:128
void setType(ValueType type)
Definition: Labeller.h:119
TypeNameMap getTypeNames() const
Definition: Labeller.h:89
int getCounterValue() const
Definition: Labeller.h:121
int m_counter
Definition: Labeller.h:451
int getSecondLevelCounterValue() const
Definition: Labeller.h:124
Relabelling label(Event e, const Event *prev=nullptr)
Return a labelled event based on the given event, previous event if supplied, and internal labeller s...
Definition: Labeller.h:171
void incrementCounter()
Definition: Labeller.h:146
std::map< ValueType, QString > TypeNameMap
Definition: Labeller.h:88
int m_counter2
Definition: Labeller.h:452
Command * labelAll(int editableId, MultiSelection *ms, const EventVector &allEvents)
Relabel all events in the given event vector that lie within the given multi-selection, according to the labelling properties of this labeller.
Definition: Labeller.h:232
Event withLabel(QString label) const
Definition: Event.h:160
Selection getContainingSelection(sv_frame_t frame, bool defaultToFollowing) const
Return the selection that contains a given frame.
Definition: Selection.cpp:196
Labeller(const Labeller &l)
Definition: Labeller.h:77
ValueType getType() const
Definition: Labeller.h:118
std::pair< Application, Event > Relabelling
Definition: Labeller.h:161
Event withValue(float value) const
Definition: Event.h:124
Event withFrame(sv_frame_t frame) const
Definition: Event.h:115
virtual ~Labeller()
Definition: Labeller.h:86
Command * subdivide(int editableId, MultiSelection *ms, const EventVector &allEvents, int n)
For each event in the given event vector (except the last), if that event lies within the given multi...
Definition: Labeller.h:279
int getCounterCycleSize() const
Definition: Labeller.h:127
std::pair< Application, Event > Revaluing
Definition: Labeller.h:162
void setCounterValue(int v)
Definition: Labeller.h:122
Command * winnow(int editableId, MultiSelection *ms, const EventVector &allEvents, int n)
The opposite of subdivide.
Definition: Labeller.h:330
void setSampleRate(sv_samplerate_t rate)
Definition: Labeller.h:138
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
Labeller(ValueType type=ValueNone)
Definition: Labeller.h:69
ValueType m_type
Definition: Labeller.h:450
bool contains(sv_frame_t frame) const
Definition: Selection.cpp:75
sv_frame_t getFrame() const
Definition: Event.h:113
sv_samplerate_t m_rate
Definition: Labeller.h:455
int m_cycle
Definition: Labeller.h:453
std::vector< Event > EventVector
Definition: Event.h:494
QString getLabel() const
Definition: Event.h:158
Revaluing revalue(Event e, const Event *prev=nullptr)
Return an event with a value following the labelling scheme, based on the given event, previous event if supplied, and internal labeller state.
Definition: Labeller.h:203
void setSecondLevelCounterValue(int v)
Definition: Labeller.h:125
Command to add or remove a series of events to or from an editable, with undo.
void resetCounters()
Definition: Labeller.h:140
int m_dp
Definition: Labeller.h:454