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