diff layer/TimeValueLayer.cpp @ 374:64e84e5efb76 spectrogram-cache-rejig

* Merge from trunk
author Chris Cannam
date Wed, 27 Feb 2008 11:59:42 +0000
parents 4f4f38a11cd2
children
line wrap: on
line diff
--- a/layer/TimeValueLayer.cpp	Mon Nov 19 15:50:37 2007 +0000
+++ b/layer/TimeValueLayer.cpp	Wed Feb 27 11:59:42 2008 +0000
@@ -23,6 +23,7 @@
 #include "view/View.h"
 
 #include "data/model/SparseTimeValueModel.h"
+#include "data/model/Labeller.h"
 
 #include "widgets/ItemEditDialog.h"
 #include "widgets/ListInputDialog.h"
@@ -35,6 +36,8 @@
 #include <QMouseEvent>
 #include <QRegExp>
 #include <QTextStream>
+#include <QMessageBox>
+#include <QInputDialog>
 
 #include <iostream>
 #include <cmath>
@@ -538,6 +541,8 @@
     int sampleRate = m_model->getSampleRate();
     if (!sampleRate) return;
 
+    paint.setRenderHint(QPainter::Antialiasing, false);
+
 //    Profiler profiler("TimeValueLayer::paint", true);
 
     int x0 = rect.left(), x1 = rect.right();
@@ -599,6 +604,9 @@
         if (m_plotStyle != PlotSegmentation) {
             textY = y - paint.fontMetrics().height()
                       + paint.fontMetrics().ascent();
+            if (textY < paint.fontMetrics().ascent() + 1) {
+                textY = paint.fontMetrics().ascent() + 1;
+            }
         }
 
 	bool haveNext = false;
@@ -940,6 +948,51 @@
 }
 
 void
+TimeValueLayer::eraseStart(View *v, QMouseEvent *e)
+{
+    if (!m_model) return;
+
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+
+    m_editingPoint = *points.begin();
+
+    if (m_editingCommand) {
+	m_editingCommand->finish();
+	m_editingCommand = 0;
+    }
+
+    m_editing = true;
+}
+
+void
+TimeValueLayer::eraseDrag(View *v, QMouseEvent *e)
+{
+}
+
+void
+TimeValueLayer::eraseEnd(View *v, QMouseEvent *e)
+{
+    if (!m_model || !m_editing) return;
+
+    m_editing = false;
+
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+    if (points.begin()->frame != m_editingPoint.frame ||
+        points.begin()->value != m_editingPoint.value) return;
+
+    m_editingCommand = new SparseTimeValueModel::EditCommand
+        (m_model, tr("Erase Point"));
+
+    m_editingCommand->deletePoint(m_editingPoint);
+
+    m_editingCommand->finish();
+    m_editingCommand = 0;
+    m_editing = false;
+}
+
+void
 TimeValueLayer::editStart(View *v, QMouseEvent *e)
 {
 //    std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
@@ -1136,7 +1189,7 @@
 }    
 
 void
-TimeValueLayer::copy(Selection s, Clipboard &to)
+TimeValueLayer::copy(View *v, Selection s, Clipboard &to)
 {
     if (!m_model) return;
 
@@ -1147,45 +1200,55 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->value, i->label);
+            point.setReferenceFrame(alignToReference(v, i->frame));
             to.addPoint(point);
         }
     }
 }
 
 bool
-TimeValueLayer::paste(const Clipboard &from, int frameOffset,
+TimeValueLayer::paste(View *v, const Clipboard &from, int frameOffset,
                       bool interactive)
 {
     if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
+    bool realign = false;
+
+    if (clipboardHasDifferentAlignment(v, from)) {
+
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted items?"),
+                                  tr("The items you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
+
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
+
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
+    }
+
     SparseTimeValueModel::EditCommand *command =
 	new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
 
-    //!!! Replace all this with a use of Labeller
-
     enum ValueAvailability {
         UnknownAvailability,
         NoValues,
         SomeValues,
         AllValues
     };
-    enum ValueGeneration {
-        GenerateNone,
-        GenerateFromCounter,
-        GenerateFromFrameNumber,
-        GenerateFromRealTime,
-        GenerateFromRealTimeDifference,
-        GenerateFromTempo,
-        GenerateFromExistingNeighbour,
-        GenerateFromLabels
-    };
 
-    ValueGeneration generation = GenerateNone;
+    Labeller::ValueType generation = Labeller::ValueNone;
 
     bool haveUsableLabels = false;
     bool haveExistingItems = !(m_model->isEmpty());
+    Labeller labeller;
+    labeller.setSampleRate(m_model->getSampleRate());
 
     if (interactive) {
 
@@ -1232,38 +1295,18 @@
                 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
             }
 
+            Labeller::TypeNameMap names = labeller.getTypeNames();
+
             QStringList options;
-            std::vector<int> genopts;
+            std::vector<Labeller::ValueType> genopts;
 
-            options << tr("Zero for all items");
-            genopts.push_back(int(GenerateNone));
-
-            options << tr("Whole numbers counting from 1");
-            genopts.push_back(int(GenerateFromCounter));
-
-            options << tr("Item's audio sample frame number");
-            genopts.push_back(int(GenerateFromFrameNumber));
-
-            options << tr("Item's time in seconds");
-            genopts.push_back(int(GenerateFromRealTime));
-
-            options << tr("Duration from the item to the following item");
-            genopts.push_back(int(GenerateFromRealTimeDifference));
-
-            options << tr("Tempo in bpm derived from the duration");
-            genopts.push_back(int(GenerateFromTempo));
-
-            if (haveExistingItems) {
-                options << tr("Value of the nearest existing item");
-                genopts.push_back(int(GenerateFromExistingNeighbour));
+            for (Labeller::TypeNameMap::const_iterator i = names.begin();
+                 i != names.end(); ++i) {
+                if (i->first == Labeller::ValueNone) options << tr("Zero for all items");
+                else options << i->second;
+                genopts.push_back(i->first);
             }
 
-            if (haveUsableLabels) {
-                options << tr("Value extracted from the item's label (where possible)");
-                genopts.push_back(int(GenerateFromLabels));
-            }
-
-
             static int prevSelection = 0;
 
             bool ok = false;
@@ -1273,32 +1316,54 @@
 
             if (!ok) return false;
             int selection = 0;
-            generation = GenerateNone;
+            generation = Labeller::ValueNone;
 
             for (QStringList::const_iterator i = options.begin();
                  i != options.end(); ++i) {
                 if (selected == *i) {
-                    generation = ValueGeneration(genopts[selection]);
+                    generation = genopts[selection];
                     break;
                 }
                 ++selection;
             }
+            
+            labeller.setType(generation);
+
+            if (generation == Labeller::ValueFromCyclicalCounter ||
+                generation == Labeller::ValueFromTwoLevelCounter) {
+                int cycleSize = QInputDialog::getInteger
+                    (0, tr("Select cycle size"),
+                     tr("Cycle size:"), 4, 2, 16, 1);
+                labeller.setCounterCycleSize(cycleSize);
+            }
 
             prevSelection = selection;
         }
     }
 
-    int counter = 1;
-    float prevBpm = 120.f;
+    SparseTimeValueModel::Point prevPoint(0);
 
     for (Clipboard::PointList::const_iterator i = points.begin();
          i != points.end(); ++i) {
         
         if (!i->haveFrame()) continue;
+
         size_t frame = 0;
-        if (frameOffset > 0 || -frameOffset < i->getFrame()) {
-            frame = i->getFrame() + frameOffset;
+
+        if (!realign) {
+            
+            frame = i->getFrame();
+
+        } else {
+
+            if (i->haveReferenceFrame()) {
+                frame = i->getReferenceFrame();
+                frame = alignFromReference(v, frame);
+            } else {
+                frame = i->getFrame();
+            }
         }
+
         SparseTimeValueModel::Point newPoint(frame);
   
         if (i->haveLabel()) {
@@ -1307,81 +1372,33 @@
             newPoint.label = QString("%1").arg(i->getValue());
         }
 
+        bool usePrev = false;
+        SparseTimeValueModel::Point formerPrevPoint = prevPoint;
+
         if (i->haveValue()) {
             newPoint.value = i->getValue();
         } else {
-            
-            switch (generation) {
-
-            case GenerateNone:
-                newPoint.value = 0;
-                break;
-
-            case GenerateFromCounter:
-                newPoint.value = counter;
-                break;
-
-            case GenerateFromFrameNumber:
-                newPoint.value = frame;
-                break;
-
-            case GenerateFromRealTime: 
-                newPoint.value = float(frame) / float(m_model->getSampleRate());
-                break;
-
-            case GenerateFromRealTimeDifference:
-            case GenerateFromTempo:
-            {
-                size_t nextFrame = frame;
-                Clipboard::PointList::const_iterator j = i;
-                for (; j != points.end(); ++j) {
-                    if (!j->haveFrame()) continue;
-                    if (j != i) break;
-                }
-                if (j != points.end()) {
-                    nextFrame = j->getFrame();
-                }
-                if (generation == GenerateFromRealTimeDifference) {
-                    newPoint.value = float(nextFrame - frame) /
-                        float(m_model->getSampleRate());
-                } else {
-                    float bpm = prevBpm;
-                    if (nextFrame > frame) {
-                        bpm = (60.f * m_model->getSampleRate()) /
-                            (nextFrame - frame);
-                    }
-                    newPoint.value = bpm;
-                    prevBpm = bpm;
-                }
-                break;
-            }
-
-            case GenerateFromExistingNeighbour:
-            {
-                SparseTimeValueModel::PointList points = 
-                    m_model->getPoints(frame);
-                if (points.empty()) points = m_model->getPreviousPoints(frame);
-                if (points.empty()) points = m_model->getNextPoints(frame);
-                if (points.empty()) {
-                    newPoint.value = 0.f;
-                } else {
-                    newPoint.value = points.begin()->value;
-                }
-            }
-
-            case GenerateFromLabels:
-                if (i->haveLabel()) {
-                    // more forgiving than QString::toFloat()
-                    newPoint.value = atof(i->getLabel().toLocal8Bit());
-                } else {
-                    newPoint.value = 0.f;
-                }
+//            std::cerr << "Setting value on point at " << newPoint.frame << " from labeller";
+//            if (i == points.begin()) {
+//                std::cerr << ", no prev point" << std::endl;
+//            } else {
+//                std::cerr << ", prev point is at " << prevPoint.frame << std::endl;
+//            }
+            labeller.setValue<SparseTimeValueModel::Point>
+                (newPoint, (i == points.begin()) ? 0 : &prevPoint);
+//            std::cerr << "New point value = " << newPoint.value << std::endl;
+            if (labeller.actingOnPrevPoint() && i != points.begin()) {
+                usePrev = true;
             }
         }
-        
+
+        if (usePrev) {
+            command->deletePoint(formerPrevPoint);
+            command->addPoint(prevPoint);
+        }
+
+        prevPoint = newPoint;
         command->addPoint(newPoint);
-        
-        ++counter;
     }
 
     command->finish();