# HG changeset patch # User Chris Cannam # Date 1173372788 0 # Node ID 9465b5375235b323df6cc7857c28ad45bad0a94a # Parent 403bfb88d8d6519a6e1cdbe73fc0db5b625a2485 * Fix #1672407 confused by plugin-named files in cwd (or home?) * Fix #1491848 crash when loading new file while transform plugin runs * Fix #1502287 Background remains black after spectrogram layer deleted * Fix #1604477 Replacing the main audio file silences secondary audio file * Fix failure to initialise property box layout to last preference on startup * Fix resample/wrong-rate display in Pane, ensure that right rate is chosen if all current models have an acceptable rate even if previous main model had a different one * Fix "global zoom" broken in previous commit * Some fixes to spectrogram cache area updating (makes spectrogram appear more quickly, previously it had a tendency to refresh with empty space) * Fixes to colour 3d plot normalization diff -r 403bfb88d8d6 -r 9465b5375235 layer/Colour3DPlotLayer.cpp --- a/layer/Colour3DPlotLayer.cpp Wed Mar 07 18:00:49 2007 +0000 +++ b/layer/Colour3DPlotLayer.cpp Thu Mar 08 16:53:08 2007 +0000 @@ -384,7 +384,7 @@ { m_model->getColumn(col, values); - float colMax = 0.f; + float colMax = 0.f, colMin = 0.f; float min = 0.f, max = 0.f; if (m_normalizeColumns) { @@ -394,11 +394,10 @@ if (m_normalizeColumns) { for (size_t y = 0; y < values.size(); ++y) { - if (values[y] > colMax || y == 0) colMax = values[y]; + if (y == 0 || values[y] > colMax) colMax = values[y]; + if (y == 0 || values[y] < colMin) colMin = values[y]; } - if (m_colourScale == LogScale) { - colMax = LogRange::map(colMax); - } + if (colMin == colMax) colMax = colMin + 1; } for (size_t y = 0; y < values.size(); ++y) { @@ -406,16 +405,10 @@ float value = min; value = values[y]; - if (m_colourScale == LogScale) { - value = LogRange::map(value); - } if (m_normalizeColumns) { - if (colMax != 0) { - value = max * (value / colMax); - } else { - value = 0; - } + float norm = (value - colMin) / (colMax - colMin); + value = min + (max - min) * norm; } values[y] = value; @@ -429,7 +422,7 @@ size_t modelEnd = m_model->getEndFrame(); size_t modelResolution = m_model->getResolution(); - std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl; +// std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl; if (!m_normalizeVisibleArea || m_normalizeColumns) { firstBin = modelStart / modelResolution; @@ -453,7 +446,7 @@ m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8); m_cacheStart = firstBin; - std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " starting " << m_cacheStart << std::endl; +// std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " starting " << m_cacheStart << std::endl; m_cache->setNumColors(256); DenseThreeDimensionalModel::Column values; @@ -480,7 +473,7 @@ m_cache->fill(0); - float visibleMax = 0.f; + float visibleMax = 0.f, visibleMin = 0.f; if (m_normalizeVisibleArea && !m_normalizeColumns) { @@ -489,17 +482,21 @@ values.clear(); getColumn(c, values); - float colMax = 0.f; + float colMax = 0.f, colMin = 0.f; for (size_t y = 0; y < m_model->getHeight(); ++y) { if (y >= values.size()) break; if (y == 0 || values[y] > colMax) colMax = values[y]; + if (y == 0 || values[y] < colMin) colMin = values[y]; } if (c == firstBin || colMax > visibleMax) visibleMax = colMax; + if (c == firstBin || colMin < visibleMin) visibleMin = colMin; } } + if (visibleMin == visibleMax) visibleMax = visibleMin + 1; + for (size_t c = firstBin; c <= lastBin; ++c) { values.clear(); @@ -513,9 +510,12 @@ } if (m_normalizeVisibleArea && !m_normalizeColumns) { - if (visibleMax != 0) { - value = max * (value / visibleMax); - } + float norm = (value - visibleMin) / (visibleMax - visibleMin); + value = min + (max - min) * norm; + } + + if (m_colourScale == LogScale) { + value = LogRange::map(value); } int pixel = int(((value - min) * 256) / (max - min)); diff -r 403bfb88d8d6 -r 9465b5375235 layer/Layer.h --- a/layer/Layer.h Wed Mar 07 18:00:49 2007 +0000 +++ b/layer/Layer.h Thu Mar 08 16:53:08 2007 +0000 @@ -84,6 +84,9 @@ virtual VerticalPosition getPreferredFrameCountPosition() const { return PositionBottom; } + virtual bool hasLightBackground() const { + return true; + } virtual QString getPropertyContainerIconName() const; diff -r 403bfb88d8d6 -r 9465b5375235 layer/SpectrogramLayer.cpp --- a/layer/SpectrogramLayer.cpp Wed Mar 07 18:00:49 2007 +0000 +++ b/layer/SpectrogramLayer.cpp Thu Mar 08 16:53:08 2007 +0000 @@ -81,7 +81,7 @@ setColourScale(LinearColourScale); setColourMap(ColourMapper::Sunset); setFrequencyScale(LogFrequencyScale); - setGain(20); +// setGain(20); } else if (config == MelodicPeaks) { setWindowSize(4096); setWindowHopLevel(5); @@ -1015,6 +1015,12 @@ } } +bool +SpectrogramLayer::hasLightBackground() const +{ + return (m_colourMap == (int)ColourMapper::BlackOnWhite); +} + void SpectrogramLayer::initialisePalette() { @@ -1112,9 +1118,10 @@ min = m_viewMags[v].getMin(); max = m_viewMags[v].getMax(); } else if (!m_normalizeColumns) { - if (m_colourScale == LinearColourScale || - m_colourScale == MeterColourScale) { -// max = 0.1f; + if (m_colourScale == LinearColourScale //|| +// m_colourScale == MeterColourScale) { + ) { + max = 0.1f; } } @@ -1687,12 +1694,6 @@ void SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const { - if (m_colourMap == (int)ColourMapper::BlackOnWhite) { - v->setLightBackground(true); - } else { - v->setLightBackground(false); - } - Profiler profiler("SpectrogramLayer::paint", true); #ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << std::endl; @@ -1742,15 +1743,11 @@ int x0 = 0; int x1 = v->width(); - int y0 = 0; - int y1 = v->height(); bool recreateWholePixmapCache = true; x0 = rect.left(); x1 = rect.right() + 1; - y0 = rect.top(); - y1 = rect.bottom() + 1; if (cache.validArea.width() > 0) { @@ -1852,20 +1849,23 @@ } else { #ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "SpectrogramLayer: pixmap cache useless" << std::endl; + if (int(cache.zoomLevel) != zoomLevel) { + std::cerr << "(cache zoomLevel " << cache.zoomLevel + << " != " << zoomLevel << ")" << std::endl; + } + if (cache.pixmap.width() != v->width()) { + std::cerr << "(cache width " << cache.pixmap.width() + << " != " << v->width(); + } + if (cache.pixmap.height() != v->height()) { + std::cerr << "(cache height " << cache.pixmap.height() + << " != " << v->height(); + } #endif cache.validArea = QRect(); } } -/* - if (stillCacheing) { - x0 = rect.left(); - x1 = rect.right() + 1; - y0 = rect.top(); - y1 = rect.bottom() + 1; - } -*/ - if (updateViewMagnitudes(v)) { #ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; @@ -1906,7 +1906,17 @@ if (paintBlockWidth < 20) paintBlockWidth = 20; +#ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << std::endl; +#endif + + // We always paint the full height when refreshing the cache. + // Smaller heights can be used when painting direct from cache + // (further up in this function), but we want to ensure the cache + // is coherent without having to worry about vertical matching of + // required and valid areas as well as horizontal. + + int h = v->height(); if (cache.validArea.width() > 0) { @@ -1956,11 +1966,10 @@ x1 = x0 + paintBlockWidth; } } - cache.validArea = QRect(x0, 0, x1 - x0, v->height()); + cache.validArea = QRect(x0, 0, x1 - x0, h); } int w = x1 - x0; - int h = y1 - y0; #ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << std::endl; @@ -2033,13 +2042,16 @@ } } - #ifdef DEBUG_SPECTROGRAM_REPAINT - std::cerr << (float(v->getFrameForX(1) - v->getFrameForX(0)) / increment) << " bins per pixel" << std::endl; + std::cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << std::endl; #endif + bool runOutOfData = false; + for (int x = 0; x < w; ++x) { + if (runOutOfData) break; + for (int y = 0; y < h; ++y) { ymag[y] = 0.f; ydiv[y] = 0.f; @@ -2065,7 +2077,14 @@ for (int s = s0i; s <= s1i; ++s) { - if (!fft->isColumnAvailable(s)) continue; + if (!fft->isColumnAvailable(s)) { +#ifdef DEBUG_SPECTROGRAM_REPAINT + std::cerr << "Met unavailable column at col " << s << std::endl; +#endif +// continue; + runOutOfData = true; + break; + } if (!fftSuspended) { fft->suspendWrites(); @@ -2236,14 +2255,26 @@ Profiler profiler2("SpectrogramLayer::paint: draw image", true); - paint.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); +#ifdef DEBUG_SPECTROGRAM_REPAINT + std::cerr << "Painting " << w << "x" << rect.height() + << " from draw buffer at " << 0 << "," << rect.y() + << " to window at " << x0 << "," << rect.y() << std::endl; +#endif + + paint.drawImage(x0, rect.y(), m_drawBuffer, 0, rect.y(), w, rect.height()); if (recreateWholePixmapCache) { - cache.pixmap = QPixmap(v->width(), v->height()); + cache.pixmap = QPixmap(v->width(), h); } +#ifdef DEBUG_SPECTROGRAM_REPAINT + std::cerr << "Painting " << w << "x" << h + << " from draw buffer at " << 0 << "," << 0 + << " to cache at " << x0 << "," << 0 << std::endl; +#endif + QPainter cachePainter(&cache.pixmap); - cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); + cachePainter.drawImage(x0, 0, m_drawBuffer, 0, 0, w, h); cachePainter.end(); if (!m_normalizeVisibleArea || !overallMagChanged) { @@ -2256,7 +2287,7 @@ std::cerr << "SpectrogramLayer::paint() updating left (0, " << cache.validArea.x() << ")" << std::endl; #endif - v->update(0, 0, cache.validArea.x(), v->height()); + v->update(0, 0, cache.validArea.x(), h); } if (cache.validArea.x() + cache.validArea.width() < @@ -2273,7 +2304,7 @@ 0, cache.pixmap.width() - (cache.validArea.x() + cache.validArea.width()), - v->height()); + h); } } else { // overallMagChanged @@ -2356,7 +2387,9 @@ if (m_fftModels.find(v) == m_fftModels.end()) return 100; size_t completion = m_fftModels[v].first->getCompletion(); +#ifdef DEBUG_SPECTROGRAM_REPAINT std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; +#endif return completion; } diff -r 403bfb88d8d6 -r 9465b5375235 layer/SpectrogramLayer.h --- a/layer/SpectrogramLayer.h Wed Mar 07 18:00:49 2007 +0000 +++ b/layer/SpectrogramLayer.h Thu Mar 08 16:53:08 2007 +0000 @@ -71,6 +71,8 @@ size_t &resolution, SnapType snap) const; + virtual bool hasLightBackground() const; + void setModel(const DenseTimeValueModel *model); virtual PropertyList getProperties() const; diff -r 403bfb88d8d6 -r 9465b5375235 view/Pane.cpp --- a/view/Pane.cpp Wed Mar 07 18:00:49 2007 +0000 +++ b/view/Pane.cpp Thu Mar 08 16:53:08 2007 +0000 @@ -233,8 +233,6 @@ width() > 120 && height() > 100) { if (!m_headsUpDisplay->isVisible()) { m_headsUpDisplay->show(); - connect(m_manager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), - this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); } if (haveVThumb) { m_headsUpDisplay->setFixedHeight(m_vthumb->height() + m_hthumb->height()); @@ -245,10 +243,6 @@ } } else { m_headsUpDisplay->hide(); - if (m_manager) { - disconnect(m_manager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), - this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); - } } } @@ -571,22 +565,24 @@ r.y() + r.height() >= height() - fontHeight - 6) { size_t modelRate = waveformModel->getSampleRate(); - size_t mainModelRate = m_manager->getMainModelSampleRate(); size_t playbackRate = m_manager->getPlaybackSampleRate(); - + size_t outputRate = m_manager->getOutputSampleRate(); + QString srNote = ""; // Show (R) for waveform models that will be resampled on // playback, and (X) for waveform models that will be played - // at the wrong rate because their rate differs from that of - // the main model. + // at the wrong rate because their rate differs from the + // current playback rate (which is not necessarily that of the + // main model). - if (modelRate == mainModelRate) { - if (modelRate != playbackRate) srNote = " " + tr("(R)"); - } else { -// std::cerr << "Sample rate = " << modelRate << ", main model rate = " << mainModelRate << std::endl; - srNote = " " + tr("(X)"); - } + if (playbackRate != 0) { + if (modelRate == playbackRate) { + if (modelRate != outputRate) srNote = " " + tr("(R)"); + } else { + srNote = " " + tr("(X)"); + } + } QString desc = tr("%1 / %2Hz%3") .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(), @@ -1628,11 +1624,15 @@ } void -Pane::viewZoomLevelChanged(View *v, unsigned long, bool locked) +Pane::viewZoomLevelChanged(View *v, unsigned long z, bool locked) { // std::cerr << "Pane[" << this << "]::zoomLevelChanged (global now " // << (m_manager ? m_manager->getGlobalZoom() : 0) << ")" << std::endl; + View::viewZoomLevelChanged(v, z, locked); + + if (!m_vthumb->isVisible()) return; + if (v != this) { if (!locked || !m_followZoom) return; } diff -r 403bfb88d8d6 -r 9465b5375235 view/View.cpp --- a/view/View.cpp Wed Mar 07 18:00:49 2007 +0000 +++ b/view/View.cpp Thu Mar 08 16:53:08 2007 +0000 @@ -44,7 +44,6 @@ m_followZoom(true), m_followPlay(PlaybackScrollPage), m_playPointerFrame(0), - m_lightBackground(true), m_showProgress(showProgress), m_cache(0), m_cacheCentreFrame(0), @@ -431,6 +430,16 @@ } } +bool +View::hasLightBackground() const +{ + for (LayerList::const_iterator i = m_layers.begin(); + i != m_layers.end(); ++i) { + if (!(*i)->hasLightBackground()) return false; + } + return true; +} + View::LayerProgressBar::LayerProgressBar(QWidget *parent) : QProgressBar(parent) { @@ -1614,14 +1623,13 @@ "followPan=\"%3\" " "followZoom=\"%4\" " "tracking=\"%5\" " - "light=\"%6\" %7>\n") + " %6>\n") .arg(m_centreFrame) .arg(m_zoomLevel) .arg(m_followPan) .arg(m_followZoom) .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" : m_followPlay == PlaybackScrollPage ? "page" : "ignore") - .arg(m_lightBackground) .arg(extraAttributes); for (size_t i = 0; i < m_layers.size(); ++i) { diff -r 403bfb88d8d6 -r 9465b5375235 view/View.h --- a/view/View.h Wed Mar 07 18:00:49 2007 +0000 +++ b/view/View.h Thu Mar 08 16:53:08 2007 +0000 @@ -171,8 +171,7 @@ virtual void setFollowGlobalZoom(bool f); virtual bool getFollowGlobalZoom() const { return m_followZoom; } - virtual void setLightBackground(bool lb) { m_lightBackground = lb; } - virtual bool hasLightBackground() const { return m_lightBackground; } + virtual bool hasLightBackground() const; enum TextStyle { BoxedText, diff -r 403bfb88d8d6 -r 9465b5375235 view/ViewManager.cpp --- a/view/ViewManager.cpp Wed Mar 07 18:00:49 2007 +0000 +++ b/view/ViewManager.cpp Thu Mar 08 16:53:08 2007 +0000 @@ -263,8 +263,17 @@ } } +size_t +ViewManager::getPlaybackSampleRate() const +{ + if (m_playSource) { + return m_playSource->getSourceSampleRate(); + } + return 0; +} + size_t -ViewManager::getPlaybackSampleRate() const +ViewManager::getOutputSampleRate() const { if (m_playSource) { return m_playSource->getTargetSampleRate(); diff -r 403bfb88d8d6 -r 9465b5375235 view/ViewManager.h --- a/view/ViewManager.h Wed Mar 07 18:00:49 2007 +0000 +++ b/view/ViewManager.h Thu Mar 08 16:53:08 2007 +0000 @@ -102,8 +102,28 @@ bool getPlaySelectionMode() const { return m_playSelectionMode; } void setPlaySelectionMode(bool on); + /** + * The sample rate that is used for playback. This is usually the + * rate of the main model, but not always. Models whose rates + * differ from this will play back at the wrong speed -- there is + * no per-model resampler. + */ size_t getPlaybackSampleRate() const; + + /** + * The sample rate of the audio output device. If the playback + * sample rate differs from this, everything will be resampled at + * the output stage. + */ + size_t getOutputSampleRate() const; + + /** + * The sample rate of the current main model. This may in theory + * differ from the playback sample rate, in which case even the + * main model will play at the wrong speed. + */ size_t getMainModelSampleRate() const { return m_mainModelSampleRate; } + void setMainModelSampleRate(size_t sr) { m_mainModelSampleRate = sr; } enum OverlayMode {