diff layer/WaveformLayer.cpp @ 25:dcdb21b62dbb

* Refactor sparse models. Previously the 1D and time-value models duplicated a lot of code; now there is a base class (SparseModel) templated on the stored point type, and the subclasses define point types with the necessary characteristics. * Add NoteModel, a new SparseModel subclass. * Reorganise local feature description display. Instead of asking the layer to draw its own, just query it for a textual description and draw that in Pane. Greatly simplifies this part of the layer code. * Add local feature descriptions to colour 3D plot and waveform layers. * Add pitch in MIDI-pitch-and-cents to spectrogram layer. * Give AudioGenerator its own mutex to shorten lock times in CallbackPlaySource. * Minor adjustments to layers menu &c
author Chris Cannam
date Thu, 02 Feb 2006 16:10:19 +0000
parents 01849cd277e6
children 38fe0ea9e46e
line wrap: on
line diff
--- a/layer/WaveformLayer.cpp	Wed Feb 01 14:49:49 2006 +0000
+++ b/layer/WaveformLayer.cpp	Thu Feb 02 16:10:19 2006 +0000
@@ -399,8 +399,8 @@
     y0 = rect.top();
     y1 = rect.bottom();
 
-    long frame0 = startFrame + x0 * zoomLevel;
-    long frame1 = startFrame + (x1 + 1) * zoomLevel;
+    long frame0 = getFrameForX(x0);
+    long frame1 = getFrameForX(x1 + 1);
      
 #ifdef DEBUG_WAVEFORM_PAINT
     std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << ")" <<  std::endl;
@@ -646,6 +646,74 @@
     }
 }
 
+QString
+WaveformLayer::getFeatureDescription(QPoint &pos) const
+{
+    int x = pos.x();
+
+    if (!m_model || !m_model->isOK()) return "";
+
+    long f0 = getFrameForX(x);
+    long f1 = getFrameForX(x + 1);
+
+    if (f0 < 0) f0 = 0;
+    if (f1 <= f0) return "";
+    
+    QString text;
+
+    RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate());
+    RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate());
+
+    if (f1 != f0 + 1 && (rt0.sec != rt1.sec || rt0.msec() != rt1.msec())) {
+	text += tr("Time:\t%1 - %2")
+	    .arg(rt0.toText(true).c_str())
+	    .arg(rt1.toText(true).c_str());
+    } else {
+	text += tr("Time:\t%1")
+	    .arg(rt0.toText(true).c_str());
+    }
+
+    size_t channels = 0, minChannel = 0, maxChannel = 0;
+    bool mergingChannels = false;
+
+    channels = getChannelArrangement(minChannel, maxChannel, mergingChannels);
+    if (channels == 0) return "";
+
+    for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
+
+	size_t blockSize = m_view->getZoomLevel();
+	RangeSummarisableTimeValueModel::RangeBlock ranges =
+	    m_model->getRanges(ch, f0, f1, blockSize);
+
+	if (ranges.empty()) continue;
+	
+	RangeSummarisableTimeValueModel::Range range = ranges[0];
+	
+	QString label = tr("Level:");
+	if (minChannel != maxChannel) {
+	    if (ch == 0) label = tr("Left:");
+	    else if (ch == 1) label = tr("Right:");
+	    else label = tr("Channel %1").arg(ch + 1);
+	}
+
+	int min = int(range.min * 1000);
+	int max = int(range.max * 1000);
+	int db = int(AudioLevel::multiplier_to_dB(std::max(fabsf(range.min),
+							   fabsf(range.max)))
+		     * 100);
+
+	if (min != max) {
+	    text += tr("\n%1\t%2 - %3 (%4 dB peak)")
+		.arg(label).arg(float(min)/1000).arg(float(max)/1000).arg(float(db)/100);
+	} else {
+	    text += tr("\n%1\t%2 (%3 dB peak)")
+		.arg(label).arg(float(min)/1000).arg(float(db)/100);
+	}
+    }
+
+    return text;
+}
+
 int
 WaveformLayer::getVerticalScaleWidth(QPainter &paint) const
 {