changeset 76:45ba0b381c5d

* Fix long-standing off-by-1 bug in WaveFileModel that was getting us the wrong values for almost all audio data when merging channels (channel == -1) * Implement cut, copy and paste * Make draw mode work properly in time value layer * Minor fixes to CSV import
author Chris Cannam
date Fri, 07 Apr 2006 17:50:33 +0000
parents dfdbf336bb37
children fd348f36c0d3
files layer/Colour3DPlotLayer.cpp layer/NoteLayer.cpp layer/NoteLayer.h layer/TextLayer.cpp layer/TextLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h layer/WaveformLayer.cpp widgets/PluginParameterDialog.cpp
diffstat 11 files changed, 336 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -333,6 +333,9 @@
 		    paint.setPen(Qt::black);//!!!
 		}
 	    }
+            
+//            std::cout << "rect " << rx0 << "," << (ry0 - h / sh - 1) << " "
+//                      << w << "x" << (h / sh + 1) << std::endl;
 
 	    paint.drawRect(r);
 
--- a/layer/NoteLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/NoteLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -727,6 +727,72 @@
     command->finish();
 }
 
+void
+NoteLayer::deleteSelection(Selection s)
+{
+    NoteModel::EditCommand *command =
+	new NoteModel::EditCommand(m_model, tr("Delete Selected Points"));
+
+    NoteModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (NoteModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+
+        if (s.contains(i->frame)) {
+            command->deletePoint(*i);
+        }
+    }
+
+    command->finish();
+}    
+
+void
+NoteLayer::copy(Selection s, Clipboard &to)
+{
+    NoteModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (NoteModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+	if (s.contains(i->frame)) {
+            Clipboard::Point point(i->frame, i->label);
+            to.addPoint(point);
+        }
+    }
+}
+
+void
+NoteLayer::paste(const Clipboard &from, int frameOffset)
+{
+    const Clipboard::PointList &points = from.getPoints();
+
+    NoteModel::EditCommand *command =
+	new NoteModel::EditCommand(m_model, tr("Paste"));
+
+    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;
+        }
+        NoteModel::Point newPoint(frame);
+  
+        if (i->haveLabel()) newPoint.label = i->getLabel();
+        if (i->haveValue()) newPoint.value = i->getValue();
+        else newPoint.value = (m_model->getValueMinimum() +
+                               m_model->getValueMaximum()) / 2;
+        if (i->haveDuration()) newPoint.duration = i->getDuration();
+        else newPoint.duration = m_model->getResolution(); //!!!
+        
+        command->addPoint(newPoint);
+    }
+
+    command->finish();
+}
+
 QString
 NoteLayer::toXmlString(QString indent, QString extraAttributes) const
 {
--- a/layer/NoteLayer.h	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/NoteLayer.h	Fri Apr 07 17:50:33 2006 +0000
@@ -52,6 +52,10 @@
 
     virtual void moveSelection(Selection s, size_t newStartFrame);
     virtual void resizeSelection(Selection s, Selection newSize);
+    virtual void deleteSelection(Selection s);
+
+    virtual void copy(Selection s, Clipboard &to);
+    virtual void paste(const Clipboard &from, int frameOffset);
 
     virtual const Model *getModel() const { return m_model; }
     void setModel(NoteModel *model);
--- a/layer/TextLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TextLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -651,6 +651,65 @@
     command->finish();
 }
 
+void
+TextLayer::deleteSelection(Selection s)
+{
+    TextModel::EditCommand *command =
+	new TextModel::EditCommand(m_model, tr("Delete Selection"));
+
+    TextModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (TextModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+	if (s.contains(i->frame)) command->deletePoint(*i);
+    }
+
+    command->finish();
+}
+
+void
+TextLayer::copy(Selection s, Clipboard &to)
+{
+    TextModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (TextModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+	if (s.contains(i->frame)) {
+            Clipboard::Point point(i->frame, i->height, i->label);
+            to.addPoint(point);
+        }
+    }
+}
+
+void
+TextLayer::paste(const Clipboard &from, int frameOffset)
+{
+    const Clipboard::PointList &points = from.getPoints();
+
+    TextModel::EditCommand *command =
+	new TextModel::EditCommand(m_model, tr("Paste"));
+
+    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;
+        }
+        TextModel::Point newPoint(frame);
+        if (i->haveValue()) newPoint.height = i->haveValue();
+        if (i->haveLabel()) newPoint.label = i->getLabel();
+        else newPoint.label = tr("New Point");
+        
+        command->addPoint(newPoint);
+    }
+
+    command->finish();
+}
+
 QString
 TextLayer::toXmlString(QString indent, QString extraAttributes) const
 {
--- a/layer/TextLayer.h	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TextLayer.h	Fri Apr 07 17:50:33 2006 +0000
@@ -50,6 +50,10 @@
 
     virtual void moveSelection(Selection s, size_t newStartFrame);
     virtual void resizeSelection(Selection s, Selection newSize);
+    virtual void deleteSelection(Selection s);
+
+    virtual void copy(Selection s, Clipboard &to);
+    virtual void paste(const Clipboard &from, int frameOffset);
 
     virtual void editOpen(View *, QMouseEvent *); // on double-click
 
--- a/layer/TimeInstantLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TimeInstantLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -19,6 +19,7 @@
 #include "base/RealTime.h"
 #include "base/View.h"
 #include "base/Profiler.h"
+#include "base/Clipboard.h"
 
 #include "model/SparseOneDimensionalModel.h"
 
@@ -689,7 +690,46 @@
 
     command->finish();
 }
-  
+
+void
+TimeInstantLayer::copy(Selection s, Clipboard &to)
+{
+    SparseOneDimensionalModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (SparseOneDimensionalModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+	if (s.contains(i->frame)) {
+            Clipboard::Point point(i->frame, i->label);
+            to.addPoint(point);
+        }
+    }
+}
+
+void
+TimeInstantLayer::paste(const Clipboard &from, int frameOffset)
+{
+    const Clipboard::PointList &points = from.getPoints();
+
+    SparseOneDimensionalModel::EditCommand *command =
+	new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste"));
+
+    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;
+        }
+        SparseOneDimensionalModel::Point newPoint(frame);
+        if (i->haveLabel()) newPoint.label = i->getLabel();
+        
+        command->addPoint(newPoint);
+    }
+
+    command->finish();
+}
 
 QString
 TimeInstantLayer::toXmlString(QString indent, QString extraAttributes) const
--- a/layer/TimeInstantLayer.h	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TimeInstantLayer.h	Fri Apr 07 17:50:33 2006 +0000
@@ -54,6 +54,9 @@
     virtual void resizeSelection(Selection s, Selection newSize);
     virtual void deleteSelection(Selection s);
 
+    virtual void copy(Selection s, Clipboard &to);
+    virtual void paste(const Clipboard &from, int frameOffset);
+
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseOneDimensionalModel *model);
 
--- a/layer/TimeValueLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -502,7 +502,8 @@
 	int y = getYForValue(v, p.value);
 
 	bool haveNext = false;
-	int nx = v->getXForFrame(m_model->getEndFrame());
+	int nx = v->getXForFrame(v->getModelsEndFrame());
+// m_model->getEndFrame());
 	int ny = y;
 
 	SparseTimeValueModel::PointList::const_iterator j = i;
@@ -513,7 +514,10 @@
 	    nx = v->getXForFrame(q.frame);
 	    ny = getYForValue(v, q.value);
 	    haveNext = true;
-	}
+        }
+
+//        std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext 
+//                  << ", nx = " << nx << std::endl;
 
 	int labelY = y;
 
@@ -608,6 +612,8 @@
 	}
 
 	if (m_plotStyle == PlotSegmentation) {
+
+//            std::cerr << "drawing rect" << std::endl;
 	    
 	    if (nx <= x) continue;
 
@@ -728,18 +734,40 @@
     if (!m_model) return;
 
     long frame = v->getFrameForX(e->x());
+    long resolution = m_model->getResolution();
     if (frame < 0) frame = 0;
-    frame = frame / m_model->getResolution() * m_model->getResolution();
+    frame = (frame / resolution) * resolution;
 
     float value = getValueForY(v, e->y());
 
-    m_editingPoint = SparseTimeValueModel::Point(frame, value, tr("New Point"));
+    bool havePoint = false;
+
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+    if (!points.empty()) {
+        for (SparseTimeValueModel::PointList::iterator i = points.begin();
+             i != points.end(); ++i) {
+            if (((i->frame / resolution) * resolution) != frame) {
+                std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
+                continue;
+            }
+            m_editingPoint = *i;
+            havePoint = true;
+        }
+    }
+
+    if (!havePoint) {
+        m_editingPoint = SparseTimeValueModel::Point
+            (frame, value, tr("New Point"));
+    }
+
     m_originalPoint = m_editingPoint;
 
     if (m_editingCommand) m_editingCommand->finish();
     m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
 							     tr("Draw Point"));
-    m_editingCommand->addPoint(m_editingPoint);
+    if (!havePoint) {
+        m_editingCommand->addPoint(m_editingPoint);
+    }
 
     m_editing = true;
 }
@@ -752,12 +780,45 @@
     if (!m_model || !m_editing) return;
 
     long frame = v->getFrameForX(e->x());
+    long resolution = m_model->getResolution();
     if (frame < 0) frame = 0;
-    frame = frame / m_model->getResolution() * m_model->getResolution();
+    frame = (frame / resolution) * resolution;
 
     float value = getValueForY(v, e->y());
 
-    m_editingCommand->deletePoint(m_editingPoint);
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+
+    std::cerr << points.size() << " points" << std::endl;
+
+    bool havePoint = false;
+
+    if (!points.empty()) {
+        for (SparseTimeValueModel::PointList::iterator i = points.begin();
+             i != points.end(); ++i) {
+            if (i->frame == m_editingPoint.frame &&
+                i->value == m_editingPoint.value) {
+                std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl;
+                continue;
+            }
+            if (((i->frame / resolution) * resolution) != frame) {
+                std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
+                continue;
+            }
+            std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl;
+            m_editingPoint = *i;
+            m_originalPoint = m_editingPoint;
+            m_editingCommand->deletePoint(m_editingPoint);
+            havePoint = true;
+        }
+    }
+
+    if (!havePoint) {
+        if (frame == m_editingPoint.frame) {
+            m_editingCommand->deletePoint(m_editingPoint);
+        }
+    }
+
+//    m_editingCommand->deletePoint(m_editingPoint);
     m_editingPoint.frame = frame;
     m_editingPoint.value = value;
     m_editingCommand->addPoint(m_editingPoint);
@@ -941,6 +1002,71 @@
     command->finish();
 }
 
+void
+TimeValueLayer::deleteSelection(Selection s)
+{
+    SparseTimeValueModel::EditCommand *command =
+	new SparseTimeValueModel::EditCommand(m_model,
+					      tr("Delete Selected Points"));
+
+    SparseTimeValueModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (SparseTimeValueModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+
+        if (s.contains(i->frame)) {
+            command->deletePoint(*i);
+        }
+    }
+
+    command->finish();
+}    
+
+void
+TimeValueLayer::copy(Selection s, Clipboard &to)
+{
+    SparseTimeValueModel::PointList points =
+	m_model->getPoints(s.getStartFrame(), s.getEndFrame());
+
+    for (SparseTimeValueModel::PointList::iterator i = points.begin();
+	 i != points.end(); ++i) {
+	if (s.contains(i->frame)) {
+            Clipboard::Point point(i->frame, i->label);
+            to.addPoint(point);
+        }
+    }
+}
+
+void
+TimeValueLayer::paste(const Clipboard &from, int frameOffset)
+{
+    const Clipboard::PointList &points = from.getPoints();
+
+    SparseTimeValueModel::EditCommand *command =
+	new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
+
+    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;
+        }
+        SparseTimeValueModel::Point newPoint(frame);
+  
+        if (i->haveLabel()) newPoint.label = i->getLabel();
+        if (i->haveValue()) newPoint.value = i->getValue();
+        else newPoint.value = (m_model->getValueMinimum() +
+                               m_model->getValueMaximum()) / 2;
+        
+        command->addPoint(newPoint);
+    }
+
+    command->finish();
+}
+
 QString
 TimeValueLayer::toXmlString(QString indent, QString extraAttributes) const
 {
--- a/layer/TimeValueLayer.h	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/TimeValueLayer.h	Fri Apr 07 17:50:33 2006 +0000
@@ -55,6 +55,10 @@
 
     virtual void moveSelection(Selection s, size_t newStartFrame);
     virtual void resizeSelection(Selection s, Selection newSize);
+    virtual void deleteSelection(Selection s);
+
+    virtual void copy(Selection s, Clipboard &to);
+    virtual void paste(const Clipboard &from, int frameOffset);
 
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseTimeValueModel *model);
--- a/layer/WaveformLayer.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/layer/WaveformLayer.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -892,18 +892,31 @@
 	    else label = tr("Channel %1").arg(ch + 1);
 	}
 
-	int min = int(range.min * 1000);
-	int max = int(range.max * 1000);
+        bool singleValue = false;
+        float min, max;
+
+        if (fabs(range.min) < 0.01) {
+            min = range.min;
+            max = range.max;
+            singleValue = (min == max);
+        } else {
+            int imin = int(range.min * 1000);
+            int imax = int(range.max * 1000);
+            singleValue = (imin == imax);
+            min = float(imin)/1000;
+            max = float(imax)/1000;
+        }
+
 	int db = int(AudioLevel::multiplier_to_dB(std::max(fabsf(range.min),
 							   fabsf(range.max)))
 		     * 100);
 
-	if (min != max) {
+	if (!singleValue) {
 	    text += tr("\n%1\t%2 - %3 (%4 dB peak)")
-		.arg(label).arg(float(min)/1000).arg(float(max)/1000).arg(float(db)/100);
+		.arg(label).arg(min).arg(max).arg(float(db)/100);
 	} else {
 	    text += tr("\n%1\t%2 (%3 dB peak)")
-		.arg(label).arg(float(min)/1000).arg(float(db)/100);
+		.arg(label).arg(min).arg(float(db)/100);
 	}
     }
 
--- a/widgets/PluginParameterDialog.cpp	Thu Apr 06 12:12:41 2006 +0000
+++ b/widgets/PluginParameterDialog.cpp	Fri Apr 07 17:50:33 2006 +0000
@@ -131,7 +131,7 @@
                 channelLayout->addWidget(new QLabel(tr("This plugin only has a single channel input,\nbut the source has %1 channels.").arg(sourceChannels)));
 
                 QComboBox *channelCombo = new QComboBox;
-                channelCombo->addItem(tr("Use sum of source channels"));
+                channelCombo->addItem(tr("Use mean of source channels"));
                 for (int i = 0; i < sourceChannels; ++i) {
                     channelCombo->addItem(tr("Use channel %1 only").arg(i + 1));
                 }