comparison layer/TimeValueLayer.cpp @ 125:999ae0f7d10c

* Change preferences dialog to ok/apply/cancel model * Make preferences persist in a config file * Change instance() to getInstance() for all singleton types * Make pasting to time-value layer with no values in clipboard ask you how to generate the values * Fix bad behaviour caused by importing "data"-type (i.e. 3d dense) model from annotation file without a fixed window size available
author Chris Cannam
date Thu, 27 Jul 2006 16:06:32 +0000
parents 0f36cdf407a6
children 33929e0c3c6b
comparison
equal deleted inserted replaced
124:bd6e85b3d88b 125:999ae0f7d10c
21 #include "base/View.h" 21 #include "base/View.h"
22 22
23 #include "model/SparseTimeValueModel.h" 23 #include "model/SparseTimeValueModel.h"
24 24
25 #include "widgets/ItemEditDialog.h" 25 #include "widgets/ItemEditDialog.h"
26 #include "widgets/ListInputDialog.h"
26 27
27 #include "SpectrogramLayer.h" // for optional frequency alignment 28 #include "SpectrogramLayer.h" // for optional frequency alignment
28 29
29 #include <QPainter> 30 #include <QPainter>
30 #include <QPainterPath> 31 #include <QPainterPath>
31 #include <QMouseEvent> 32 #include <QMouseEvent>
33 #include <QRegExp>
32 34
33 #include <iostream> 35 #include <iostream>
34 #include <cmath> 36 #include <cmath>
35 37
36 TimeValueLayer::TimeValueLayer() : 38 TimeValueLayer::TimeValueLayer() :
1129 to.addPoint(point); 1131 to.addPoint(point);
1130 } 1132 }
1131 } 1133 }
1132 } 1134 }
1133 1135
1134 void 1136 bool
1135 TimeValueLayer::paste(const Clipboard &from, int frameOffset) 1137 TimeValueLayer::paste(const Clipboard &from, int frameOffset,
1136 { 1138 bool interactive)
1137 if (!m_model) return; 1139 {
1140 if (!m_model) return false;
1138 1141
1139 const Clipboard::PointList &points = from.getPoints(); 1142 const Clipboard::PointList &points = from.getPoints();
1140 1143
1141 SparseTimeValueModel::EditCommand *command = 1144 SparseTimeValueModel::EditCommand *command =
1142 new SparseTimeValueModel::EditCommand(m_model, tr("Paste")); 1145 new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
1146
1147 enum ValueAvailability {
1148 UnknownAvailability,
1149 NoValues,
1150 SomeValues,
1151 AllValues
1152 };
1153 enum ValueGeneration {
1154 GenerateNone,
1155 GenerateFromCounter,
1156 GenerateFromFrameNumber,
1157 GenerateFromRealTime,
1158 GenerateFromRealTimeDifference,
1159 GenerateFromTempo,
1160 GenerateFromExistingNeighbour,
1161 GenerateFromLabels
1162 };
1163
1164 ValueGeneration generation = GenerateNone;
1165
1166 bool haveUsableLabels = false;
1167 bool haveExistingItems = !(m_model->isEmpty());
1168
1169 if (interactive) {
1170
1171 ValueAvailability availability = UnknownAvailability;
1172
1173 for (Clipboard::PointList::const_iterator i = points.begin();
1174 i != points.end(); ++i) {
1175
1176 if (!i->haveFrame()) continue;
1177
1178 if (availability == UnknownAvailability) {
1179 if (i->haveValue()) availability = AllValues;
1180 else availability = NoValues;
1181 continue;
1182 }
1183
1184 if (i->haveValue()) {
1185 if (availability == NoValues) {
1186 availability = SomeValues;
1187 }
1188 } else {
1189 if (availability == AllValues) {
1190 availability = SomeValues;
1191 }
1192 }
1193
1194 if (!haveUsableLabels) {
1195 if (i->haveLabel()) {
1196 if (i->getLabel().contains(QRegExp("[0-9]"))) {
1197 haveUsableLabels = true;
1198 }
1199 }
1200 }
1201
1202 if (availability == SomeValues && haveUsableLabels) break;
1203 }
1204
1205 if (availability == NoValues || availability == SomeValues) {
1206
1207 QString text;
1208 if (availability == NoValues) {
1209 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
1210 } else {
1211 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
1212 }
1213
1214 QStringList options;
1215 std::vector<int> genopts;
1216
1217 options << tr("Zero for all items");
1218 genopts.push_back(int(GenerateNone));
1219
1220 options << tr("Whole numbers counting from 1");
1221 genopts.push_back(int(GenerateFromCounter));
1222
1223 options << tr("Item's audio sample frame number");
1224 genopts.push_back(int(GenerateFromFrameNumber));
1225
1226 options << tr("Item's time in seconds");
1227 genopts.push_back(int(GenerateFromRealTime));
1228
1229 options << tr("Duration from the item to the following item");
1230 genopts.push_back(int(GenerateFromRealTimeDifference));
1231
1232 options << tr("Tempo in bpm derived from the duration");
1233 genopts.push_back(int(GenerateFromTempo));
1234
1235 if (haveExistingItems) {
1236 options << tr("Value of the nearest existing item");
1237 genopts.push_back(int(GenerateFromExistingNeighbour));
1238 }
1239
1240 if (haveUsableLabels) {
1241 options << tr("Value extracted from the item's label (where possible)");
1242 genopts.push_back(int(GenerateFromLabels));
1243 }
1244
1245
1246 static int prevSelection = 0;
1247
1248 bool ok = false;
1249 QString selected = ListInputDialog::getItem
1250 (0, tr("Choose value calculation"),
1251 text, options, prevSelection, &ok);
1252
1253 if (!ok) return false;
1254 int selection = 0;
1255 generation = GenerateNone;
1256
1257 for (QStringList::const_iterator i = options.begin();
1258 i != options.end(); ++i) {
1259 if (selected == *i) {
1260 generation = ValueGeneration(genopts[selection]);
1261 break;
1262 }
1263 ++selection;
1264 }
1265
1266 prevSelection = selection;
1267 }
1268 }
1269
1270 int counter = 1;
1271 float prevBpm = 120.f;
1143 1272
1144 for (Clipboard::PointList::const_iterator i = points.begin(); 1273 for (Clipboard::PointList::const_iterator i = points.begin();
1145 i != points.end(); ++i) { 1274 i != points.end(); ++i) {
1146 1275
1147 if (!i->haveFrame()) continue; 1276 if (!i->haveFrame()) continue;
1149 if (frameOffset > 0 || -frameOffset < i->getFrame()) { 1278 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
1150 frame = i->getFrame() + frameOffset; 1279 frame = i->getFrame() + frameOffset;
1151 } 1280 }
1152 SparseTimeValueModel::Point newPoint(frame); 1281 SparseTimeValueModel::Point newPoint(frame);
1153 1282
1154 if (i->haveLabel()) newPoint.label = i->getLabel(); 1283 if (i->haveLabel()) {
1155 if (i->haveValue()) newPoint.value = i->getValue(); 1284 newPoint.label = i->getLabel();
1156 else newPoint.value = (m_model->getValueMinimum() + 1285 } else if (i->haveValue()) {
1157 m_model->getValueMaximum()) / 2; 1286 newPoint.label = QString("%1").arg(i->getValue());
1287 }
1288
1289 if (i->haveValue()) {
1290 newPoint.value = i->getValue();
1291 } else {
1292
1293 switch (generation) {
1294
1295 case GenerateNone:
1296 newPoint.value = 0;
1297 break;
1298
1299 case GenerateFromCounter:
1300 newPoint.value = counter;
1301 break;
1302
1303 case GenerateFromFrameNumber:
1304 newPoint.value = frame;
1305 break;
1306
1307 case GenerateFromRealTime:
1308 newPoint.value = float(frame) / float(m_model->getSampleRate());
1309 break;
1310
1311 case GenerateFromRealTimeDifference:
1312 case GenerateFromTempo:
1313 {
1314 size_t nextFrame = frame;
1315 Clipboard::PointList::const_iterator j = i;
1316 for (; j != points.end(); ++j) {
1317 if (!j->haveFrame()) continue;
1318 if (j != i) break;
1319 }
1320 if (j != points.end()) {
1321 nextFrame = j->getFrame();
1322 }
1323 if (generation == GenerateFromRealTimeDifference) {
1324 newPoint.value = float(nextFrame - frame) /
1325 float(m_model->getSampleRate());
1326 } else {
1327 float bpm = prevBpm;
1328 if (nextFrame > frame) {
1329 bpm = (60.f * m_model->getSampleRate()) /
1330 (nextFrame - frame);
1331 }
1332 newPoint.value = bpm;
1333 prevBpm = bpm;
1334 }
1335 break;
1336 }
1337
1338 case GenerateFromExistingNeighbour:
1339 {
1340 SparseTimeValueModel::PointList points =
1341 m_model->getPoints(frame);
1342 if (points.empty()) points = m_model->getPreviousPoints(frame);
1343 if (points.empty()) points = m_model->getNextPoints(frame);
1344 if (points.empty()) {
1345 newPoint.value = 0.f;
1346 } else {
1347 newPoint.value = points.begin()->value;
1348 }
1349 }
1350
1351 case GenerateFromLabels:
1352 if (i->haveLabel()) {
1353 // more forgiving than QString::toFloat()
1354 newPoint.value = atof(i->getLabel().toLocal8Bit());
1355 } else {
1356 newPoint.value = 0.f;
1357 }
1358 }
1359 }
1158 1360
1159 command->addPoint(newPoint); 1361 command->addPoint(newPoint);
1362
1363 ++counter;
1160 } 1364 }
1161 1365
1162 command->finish(); 1366 command->finish();
1367 return true;
1163 } 1368 }
1164 1369
1165 QString 1370 QString
1166 TimeValueLayer::toXmlString(QString indent, QString extraAttributes) const 1371 TimeValueLayer::toXmlString(QString indent, QString extraAttributes) const
1167 { 1372 {