comparison layer/TimeValueLayer.cpp @ 340:ffa448b0e1bc

* Fix #1841095 tapping time instant gives wrong time in aligned track * Fix #1815654 source tidying: Labeller * Fix (I hope) #1849999 Time value graphs one instant out
author Chris Cannam
date Thu, 13 Dec 2007 17:14:33 +0000
parents 2f83b6e3b8ca
children de4db9b5dcf1
comparison
equal deleted inserted replaced
339:ac954fc0ec6f 340:ffa448b0e1bc
21 #include "base/LogRange.h" 21 #include "base/LogRange.h"
22 #include "base/ColourDatabase.h" 22 #include "base/ColourDatabase.h"
23 #include "view/View.h" 23 #include "view/View.h"
24 24
25 #include "data/model/SparseTimeValueModel.h" 25 #include "data/model/SparseTimeValueModel.h"
26 #include "data/model/Labeller.h"
26 27
27 #include "widgets/ItemEditDialog.h" 28 #include "widgets/ItemEditDialog.h"
28 #include "widgets/ListInputDialog.h" 29 #include "widgets/ListInputDialog.h"
29 30
30 #include "SpectrogramLayer.h" // for optional frequency alignment 31 #include "SpectrogramLayer.h" // for optional frequency alignment
33 #include <QPainter> 34 #include <QPainter>
34 #include <QPainterPath> 35 #include <QPainterPath>
35 #include <QMouseEvent> 36 #include <QMouseEvent>
36 #include <QRegExp> 37 #include <QRegExp>
37 #include <QTextStream> 38 #include <QTextStream>
39 #include <QInputDialog>
38 40
39 #include <iostream> 41 #include <iostream>
40 #include <cmath> 42 #include <cmath>
41 43
42 TimeValueLayer::TimeValueLayer() : 44 TimeValueLayer::TimeValueLayer() :
1207 const Clipboard::PointList &points = from.getPoints(); 1209 const Clipboard::PointList &points = from.getPoints();
1208 1210
1209 SparseTimeValueModel::EditCommand *command = 1211 SparseTimeValueModel::EditCommand *command =
1210 new SparseTimeValueModel::EditCommand(m_model, tr("Paste")); 1212 new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
1211 1213
1212 //!!! Replace all this with a use of Labeller
1213
1214 enum ValueAvailability { 1214 enum ValueAvailability {
1215 UnknownAvailability, 1215 UnknownAvailability,
1216 NoValues, 1216 NoValues,
1217 SomeValues, 1217 SomeValues,
1218 AllValues 1218 AllValues
1219 }; 1219 };
1220 enum ValueGeneration { 1220
1221 GenerateNone, 1221 Labeller::ValueType generation = Labeller::ValueNone;
1222 GenerateFromCounter,
1223 GenerateFromFrameNumber,
1224 GenerateFromRealTime,
1225 GenerateFromRealTimeDifference,
1226 GenerateFromTempo,
1227 GenerateFromExistingNeighbour,
1228 GenerateFromLabels
1229 };
1230
1231 ValueGeneration generation = GenerateNone;
1232 1222
1233 bool haveUsableLabels = false; 1223 bool haveUsableLabels = false;
1234 bool haveExistingItems = !(m_model->isEmpty()); 1224 bool haveExistingItems = !(m_model->isEmpty());
1225 Labeller labeller;
1226 labeller.setSampleRate(m_model->getSampleRate());
1235 1227
1236 if (interactive) { 1228 if (interactive) {
1237 1229
1238 ValueAvailability availability = UnknownAvailability; 1230 ValueAvailability availability = UnknownAvailability;
1239 1231
1276 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?"); 1268 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
1277 } else { 1269 } else {
1278 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?"); 1270 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
1279 } 1271 }
1280 1272
1273 Labeller::TypeNameMap names = labeller.getTypeNames();
1274
1281 QStringList options; 1275 QStringList options;
1282 std::vector<int> genopts; 1276 std::vector<Labeller::ValueType> genopts;
1283 1277
1284 options << tr("Zero for all items"); 1278 for (Labeller::TypeNameMap::const_iterator i = names.begin();
1285 genopts.push_back(int(GenerateNone)); 1279 i != names.end(); ++i) {
1286 1280 if (i->first == Labeller::ValueNone) options << tr("Zero for all items");
1287 options << tr("Whole numbers counting from 1"); 1281 else options << i->second;
1288 genopts.push_back(int(GenerateFromCounter)); 1282 genopts.push_back(i->first);
1289
1290 options << tr("Item's audio sample frame number");
1291 genopts.push_back(int(GenerateFromFrameNumber));
1292
1293 options << tr("Item's time in seconds");
1294 genopts.push_back(int(GenerateFromRealTime));
1295
1296 options << tr("Duration from the item to the following item");
1297 genopts.push_back(int(GenerateFromRealTimeDifference));
1298
1299 options << tr("Tempo in bpm derived from the duration");
1300 genopts.push_back(int(GenerateFromTempo));
1301
1302 if (haveExistingItems) {
1303 options << tr("Value of the nearest existing item");
1304 genopts.push_back(int(GenerateFromExistingNeighbour));
1305 } 1283 }
1306
1307 if (haveUsableLabels) {
1308 options << tr("Value extracted from the item's label (where possible)");
1309 genopts.push_back(int(GenerateFromLabels));
1310 }
1311
1312 1284
1313 static int prevSelection = 0; 1285 static int prevSelection = 0;
1314 1286
1315 bool ok = false; 1287 bool ok = false;
1316 QString selected = ListInputDialog::getItem 1288 QString selected = ListInputDialog::getItem
1317 (0, tr("Choose value calculation"), 1289 (0, tr("Choose value calculation"),
1318 text, options, prevSelection, &ok); 1290 text, options, prevSelection, &ok);
1319 1291
1320 if (!ok) return false; 1292 if (!ok) return false;
1321 int selection = 0; 1293 int selection = 0;
1322 generation = GenerateNone; 1294 generation = Labeller::ValueNone;
1323 1295
1324 for (QStringList::const_iterator i = options.begin(); 1296 for (QStringList::const_iterator i = options.begin();
1325 i != options.end(); ++i) { 1297 i != options.end(); ++i) {
1326 if (selected == *i) { 1298 if (selected == *i) {
1327 generation = ValueGeneration(genopts[selection]); 1299 generation = genopts[selection];
1328 break; 1300 break;
1329 } 1301 }
1330 ++selection; 1302 ++selection;
1331 } 1303 }
1304
1305 labeller.setType(generation);
1306
1307 if (generation == Labeller::ValueFromCyclicalCounter ||
1308 generation == Labeller::ValueFromTwoLevelCounter) {
1309 int cycleSize = QInputDialog::getInteger
1310 (0, tr("Select cycle size"),
1311 tr("Cycle size:"), 4, 2, 16, 1);
1312 labeller.setCounterCycleSize(cycleSize);
1313 }
1332 1314
1333 prevSelection = selection; 1315 prevSelection = selection;
1334 } 1316 }
1335 } 1317 }
1336 1318
1337 int counter = 1; 1319 static SparseTimeValueModel::Point prevPoint(0);
1338 float prevBpm = 120.f;
1339 1320
1340 for (Clipboard::PointList::const_iterator i = points.begin(); 1321 for (Clipboard::PointList::const_iterator i = points.begin();
1341 i != points.end(); ++i) { 1322 i != points.end(); ++i) {
1342 1323
1343 if (!i->haveFrame()) continue; 1324 if (!i->haveFrame()) continue;
1354 } 1335 }
1355 1336
1356 if (i->haveValue()) { 1337 if (i->haveValue()) {
1357 newPoint.value = i->getValue(); 1338 newPoint.value = i->getValue();
1358 } else { 1339 } else {
1359 1340 labeller.setValue<SparseTimeValueModel::Point>
1360 switch (generation) { 1341 (newPoint, i == points.begin() ? 0 : &prevPoint);
1361 1342 }
1362 case GenerateNone: 1343
1363 newPoint.value = 0; 1344 prevPoint = newPoint;
1364 break;
1365
1366 case GenerateFromCounter:
1367 newPoint.value = counter;
1368 break;
1369
1370 case GenerateFromFrameNumber:
1371 newPoint.value = frame;
1372 break;
1373
1374 case GenerateFromRealTime:
1375 newPoint.value = float(frame) / float(m_model->getSampleRate());
1376 break;
1377
1378 case GenerateFromRealTimeDifference:
1379 case GenerateFromTempo:
1380 {
1381 size_t nextFrame = frame;
1382 Clipboard::PointList::const_iterator j = i;
1383 for (; j != points.end(); ++j) {
1384 if (!j->haveFrame()) continue;
1385 if (j != i) break;
1386 }
1387 if (j != points.end()) {
1388 nextFrame = j->getFrame();
1389 }
1390 if (generation == GenerateFromRealTimeDifference) {
1391 newPoint.value = float(nextFrame - frame) /
1392 float(m_model->getSampleRate());
1393 } else {
1394 float bpm = prevBpm;
1395 if (nextFrame > frame) {
1396 bpm = (60.f * m_model->getSampleRate()) /
1397 (nextFrame - frame);
1398 }
1399 newPoint.value = bpm;
1400 prevBpm = bpm;
1401 }
1402 break;
1403 }
1404
1405 case GenerateFromExistingNeighbour:
1406 {
1407 SparseTimeValueModel::PointList points =
1408 m_model->getPoints(frame);
1409 if (points.empty()) points = m_model->getPreviousPoints(frame);
1410 if (points.empty()) points = m_model->getNextPoints(frame);
1411 if (points.empty()) {
1412 newPoint.value = 0.f;
1413 } else {
1414 newPoint.value = points.begin()->value;
1415 }
1416 }
1417
1418 case GenerateFromLabels:
1419 if (i->haveLabel()) {
1420 // more forgiving than QString::toFloat()
1421 newPoint.value = atof(i->getLabel().toLocal8Bit());
1422 } else {
1423 newPoint.value = 0.f;
1424 }
1425 }
1426 }
1427
1428 command->addPoint(newPoint); 1345 command->addPoint(newPoint);
1429
1430 ++counter;
1431 } 1346 }
1432 1347
1433 command->finish(); 1348 command->finish();
1434 return true; 1349 return true;
1435 } 1350 }
1436 1351
1437 void 1352 void
1438 TimeValueLayer::toXml(QTextStream &stream, 1353 TimeValueLayer::toXml(QTextStream &stream,
1439 QString indent, QString extraAttributes) const 1354 QString indent, QString extraAttributes) const
1440 { 1355 {