Mercurial > hg > svgui
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 { |