svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-2007 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #ifndef _LABELLER_H_ 00017 #define _LABELLER_H_ 00018 00019 #include "SparseModel.h" 00020 #include "SparseValueModel.h" 00021 00022 #include "base/Selection.h" 00023 00024 #include <QObject> 00025 00026 #include <map> 00027 #include <iostream> 00028 00029 class Labeller : public QObject 00030 { 00031 Q_OBJECT 00032 00033 public: 00034 enum ValueType { 00035 ValueNone, 00036 ValueFromSimpleCounter, 00037 ValueFromCyclicalCounter, 00038 ValueFromTwoLevelCounter, 00039 ValueFromFrameNumber, 00040 ValueFromRealTime, 00041 ValueFromDurationFromPrevious, 00042 ValueFromDurationToNext, 00043 ValueFromTempoFromPrevious, 00044 ValueFromTempoToNext, 00045 ValueFromExistingNeighbour, 00046 ValueFromLabel 00047 }; 00048 00049 // uses: 00050 // 00051 // 1. when adding points to a time-value model, generate values 00052 // for those points based on their times or labels or a counter 00053 // 00054 // 2. when adding a single point to a time-instant model, generate 00055 // a label for it based on its time and that of the previous point 00056 // or a counter 00057 // 00058 // 3. when adding a single point to a time-instant model, generate 00059 // a label for the previous point based on its time and that of 00060 // the point just added (as tempo is based on time to the next 00061 // point, not the previous one) 00062 // 00063 // 4. re-label a set of points that have already been added to a 00064 // model 00065 00066 Labeller(ValueType type = ValueNone) : 00067 m_type(type), 00068 m_counter(1), 00069 m_counter2(1), 00070 m_cycle(4), 00071 m_dp(10), 00072 m_rate(0) { } 00073 00074 Labeller(const Labeller &l) : 00075 QObject(), 00076 m_type(l.m_type), 00077 m_counter(l.m_counter), 00078 m_counter2(l.m_counter2), 00079 m_cycle(l.m_cycle), 00080 m_dp(l.m_dp), 00081 m_rate(l.m_rate) { } 00082 00083 virtual ~Labeller() { } 00084 00085 typedef std::map<ValueType, QString> TypeNameMap; 00086 TypeNameMap getTypeNames() const { 00087 TypeNameMap m; 00088 m[ValueNone] 00089 = tr("No numbering"); 00090 m[ValueFromSimpleCounter] 00091 = tr("Simple counter"); 00092 m[ValueFromCyclicalCounter] 00093 = tr("Cyclical counter"); 00094 m[ValueFromTwoLevelCounter] 00095 = tr("Cyclical two-level counter (bar/beat)"); 00096 m[ValueFromFrameNumber] 00097 = tr("Audio sample frame number"); 00098 m[ValueFromRealTime] 00099 = tr("Time in seconds"); 00100 m[ValueFromDurationToNext] 00101 = tr("Duration to the following item"); 00102 m[ValueFromTempoToNext] 00103 = tr("Tempo (bpm) based on duration to following item"); 00104 m[ValueFromDurationFromPrevious] 00105 = tr("Duration since the previous item"); 00106 m[ValueFromTempoFromPrevious] 00107 = tr("Tempo (bpm) based on duration since previous item"); 00108 m[ValueFromExistingNeighbour] 00109 = tr("Same as the nearest previous item"); 00110 m[ValueFromLabel] 00111 = tr("Value extracted from the item's label (where possible)"); 00112 return m; 00113 } 00114 00115 ValueType getType() const { return m_type; } 00116 void setType(ValueType type) { m_type = type; } 00117 00118 int getCounterValue() const { return m_counter; } 00119 void setCounterValue(int v) { m_counter = v; } 00120 00121 int getSecondLevelCounterValue() const { return m_counter2; } 00122 void setSecondLevelCounterValue(int v) { m_counter2 = v; } 00123 00124 int getCounterCycleSize() const { return m_cycle; } 00125 void setCounterCycleSize(int s) { 00126 m_cycle = s; 00127 m_dp = 1; 00128 while (s > 0) { 00129 s /= 10; 00130 m_dp *= 10; 00131 } 00132 if (m_counter > m_cycle) m_counter = 1; 00133 } 00134 00135 void setSampleRate(float rate) { m_rate = rate; } 00136 00137 void resetCounters() { 00138 m_counter = 1; 00139 m_counter2 = 1; 00140 m_cycle = 4; 00141 } 00142 00143 void incrementCounter() { 00144 m_counter++; 00145 if (m_type == ValueFromCyclicalCounter || 00146 m_type == ValueFromTwoLevelCounter) { 00147 if (m_counter > m_cycle) { 00148 m_counter = 1; 00149 m_counter2++; 00150 } 00151 } 00152 } 00153 00154 template <typename PointType> 00155 void label(PointType &newPoint, PointType *prevPoint = 0) { 00156 if (m_type == ValueNone) { 00157 newPoint.label = ""; 00158 } else if (m_type == ValueFromTwoLevelCounter) { 00159 newPoint.label = tr("%1.%2").arg(m_counter2).arg(m_counter); 00160 incrementCounter(); 00161 } else if (m_type == ValueFromFrameNumber) { 00162 // avoid going through floating-point value 00163 newPoint.label = tr("%1").arg(newPoint.frame); 00164 } else { 00165 float value = getValueFor<PointType>(newPoint, prevPoint); 00166 if (actingOnPrevPoint() && prevPoint) { 00167 prevPoint->label = QString("%1").arg(value); 00168 } else { 00169 newPoint.label = QString("%1").arg(value); 00170 } 00171 } 00172 } 00173 00174 template <typename PointType> 00175 void labelAll(SparseModel<PointType> &model, MultiSelection *ms) { 00176 00177 typename SparseModel<PointType>::PointList::iterator i; 00178 typename SparseModel<PointType>::PointList pl(model.getPoints()); 00179 00180 typename SparseModel<PointType>::EditCommand *command = 00181 new typename SparseModel<PointType>::EditCommand 00182 (&model, tr("Label Points")); 00183 00184 PointType prevPoint(0); 00185 00186 for (i = pl.begin(); i != pl.end(); ++i) { 00187 00188 bool inRange = true; 00189 if (ms) { 00190 Selection s(ms->getContainingSelection(i->frame, false)); 00191 if (s.isEmpty() || !s.contains(i->frame)) { 00192 inRange = false; 00193 } 00194 } 00195 00196 PointType p(*i); 00197 00198 if (!inRange) { 00199 prevPoint = p; 00200 continue; 00201 } 00202 00203 if (actingOnPrevPoint()) { 00204 if (i != pl.begin()) { 00205 command->deletePoint(prevPoint); 00206 label<PointType>(p, &prevPoint); 00207 command->addPoint(prevPoint); 00208 } 00209 } else { 00210 command->deletePoint(p); 00211 label<PointType>(p, &prevPoint); 00212 command->addPoint(p); 00213 } 00214 00215 prevPoint = p; 00216 } 00217 00218 command->finish(); 00219 } 00220 00221 template <typename PointType> 00222 void setValue(PointType &newPoint, PointType *prevPoint = 0) { 00223 if (m_type == ValueFromExistingNeighbour) { 00224 if (!prevPoint) { 00225 std::cerr << "ERROR: Labeller::setValue: Previous point required but not provided" << std::endl; 00226 } else { 00227 newPoint.value = prevPoint->value; 00228 } 00229 } else { 00230 float value = getValueFor<PointType>(newPoint, prevPoint); 00231 if (actingOnPrevPoint() && prevPoint) { 00232 prevPoint->value = value; 00233 } else { 00234 newPoint.value = value; 00235 } 00236 } 00237 } 00238 00239 bool requiresPrevPoint() const { 00240 return (m_type == ValueFromDurationFromPrevious || 00241 m_type == ValueFromDurationToNext || 00242 m_type == ValueFromTempoFromPrevious || 00243 m_type == ValueFromDurationToNext); 00244 } 00245 00246 bool actingOnPrevPoint() const { 00247 return (m_type == ValueFromDurationToNext || 00248 m_type == ValueFromTempoToNext); 00249 } 00250 00251 protected: 00252 template <typename PointType> 00253 float getValueFor(PointType &newPoint, PointType *prevPoint) 00254 { 00255 float value = 0.f; 00256 00257 switch (m_type) { 00258 00259 case ValueNone: 00260 value = 0; 00261 break; 00262 00263 case ValueFromSimpleCounter: 00264 case ValueFromCyclicalCounter: 00265 value = m_counter; 00266 incrementCounter(); 00267 break; 00268 00269 case ValueFromTwoLevelCounter: 00270 value = m_counter2 + double(m_counter) / double(m_dp); 00271 incrementCounter(); 00272 break; 00273 00274 case ValueFromFrameNumber: 00275 value = newPoint.frame; 00276 break; 00277 00278 case ValueFromRealTime: 00279 if (m_rate == 0.f) { 00280 std::cerr << "ERROR: Labeller::getValueFor: Real-time conversion required, but no sample rate set" << std::endl; 00281 } else { 00282 value = float(newPoint.frame) / float(m_rate); 00283 } 00284 break; 00285 00286 case ValueFromDurationToNext: 00287 case ValueFromTempoToNext: 00288 case ValueFromDurationFromPrevious: 00289 case ValueFromTempoFromPrevious: 00290 if (m_rate == 0.f) { 00291 std::cerr << "ERROR: Labeller::getValueFor: Real-time conversion required, but no sample rate set" << std::endl; 00292 } else if (!prevPoint) { 00293 std::cerr << "ERROR: Labeller::getValueFor: Time difference required, but only one point provided" << std::endl; 00294 } else { 00295 int f0 = prevPoint->frame, f1 = newPoint.frame; 00296 if (m_type == ValueFromDurationToNext || 00297 m_type == ValueFromDurationFromPrevious) { 00298 value = float(f1 - f0) / m_rate; 00299 } else { 00300 if (f1 > f0) { 00301 value = (60.f * m_rate) / (f1 - f0); 00302 } 00303 } 00304 } 00305 break; 00306 00307 case ValueFromExistingNeighbour: 00308 // need to deal with this in the calling function, as this 00309 // function must handle points that don't have values to 00310 // read from 00311 break; 00312 00313 case ValueFromLabel: 00314 if (newPoint.label != "") { 00315 // more forgiving than QString::toFloat() 00316 value = atof(newPoint.label.toLocal8Bit()); 00317 } else { 00318 value = 0.f; 00319 } 00320 break; 00321 } 00322 00323 return value; 00324 } 00325 00326 ValueType m_type; 00327 int m_counter; 00328 int m_counter2; 00329 int m_cycle; 00330 int m_dp; 00331 float m_rate; 00332 }; 00333 00334 #endif