Mercurial > hg > svgui
changeset 9:561be41ad083
* Tweaked up spectrogram and added a colourmap rotation option
* Fleshed out the SV file reader code -- now we just need to hook it up
and watch it fall over
author | Chris Cannam |
---|---|
date | Mon, 16 Jan 2006 18:04:09 +0000 |
parents | 06bba0b79b1c |
children | 8f5b812baaee |
files | layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
diffstat | 2 files changed, 146 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Fri Jan 13 18:05:07 2006 +0000 +++ b/layer/SpectrogramLayer.cpp Mon Jan 16 18:04:09 2006 +0000 @@ -36,6 +36,7 @@ m_windowType(HanningWindow), m_windowOverlap(50), m_gain(1.0), + m_colourRotation(0), m_maxFrequency(8000), m_colourScale(dBColourScale), m_colourScheme(DefaultColours), @@ -108,6 +109,7 @@ list.push_back(tr("Window Size")); list.push_back(tr("Window Overlap")); list.push_back(tr("Gain")); + list.push_back(tr("Colour Rotation")); list.push_back(tr("Max Frequency")); list.push_back(tr("Frequency Scale")); return list; @@ -117,6 +119,7 @@ SpectrogramLayer::getPropertyType(const PropertyName &name) const { if (name == tr("Gain")) return RangeProperty; + if (name == tr("Colour Rotation")) return RangeProperty; return ValueProperty; } @@ -126,6 +129,7 @@ if (name == tr("Window Size") || name == tr("Window Overlap")) return tr("Window"); if (name == tr("Gain") || + name == tr("Colour Rotation") || name == tr("Colour Scale")) return tr("Scale"); if (name == tr("Max Frequency") || name == tr("Frequency Scale")) return tr("Frequency"); @@ -147,6 +151,13 @@ if (deft < *min) deft = *min; if (deft > *max) deft = *max; + } else if (name == tr("Colour Rotation")) { + + *min = 0; + *max = 256; + + deft = m_colourRotation; + } else if (name == tr("Colour Scale")) { *min = 0; @@ -218,7 +229,7 @@ QString SpectrogramLayer::getPropertyValueLabel(const PropertyName &name, - int value) const + int value) const { if (name == tr("Colour")) { switch (value) { @@ -295,6 +306,8 @@ { if (name == tr("Gain")) { setGain(pow(10, float(value)/20.0)); + } else if (name == tr("Colour Rotation")) { + setColourRotation(value); } else if (name == tr("Colour")) { if (m_view) m_view->setLightBackground(value == 2); switch (value) { @@ -354,11 +367,12 @@ m_pixmapCacheInvalid = true; m_channel = ch; + + m_mutex.unlock(); + emit layerParametersChanged(); - - m_mutex.unlock(); + fillCache(); - } int @@ -377,11 +391,12 @@ m_pixmapCacheInvalid = true; m_windowSize = ws; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); + fillCache(); - } size_t @@ -400,9 +415,11 @@ m_pixmapCacheInvalid = true; m_windowOverlap = wi; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); + fillCache(); } @@ -422,9 +439,11 @@ m_pixmapCacheInvalid = true; m_windowType = w; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); + fillCache(); } @@ -444,9 +463,11 @@ m_pixmapCacheInvalid = true; m_gain = gain; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); + fillCache(); } @@ -466,9 +487,10 @@ m_pixmapCacheInvalid = true; m_maxFrequency = mf; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); } size_t @@ -478,6 +500,27 @@ } void +SpectrogramLayer::setColourRotation(int r) +{ + m_mutex.lock(); + // don't need to invalidate main cache here + m_pixmapCacheInvalid = true; + + if (r < 0) r = 0; + if (r > 256) r = 256; + int distance = r - m_colourRotation; + + if (distance != 0) { + rotateCacheColourmap(-distance); + m_colourRotation = r; + } + + m_mutex.unlock(); + + emit layerParametersChanged(); +} + +void SpectrogramLayer::setColourScale(ColourScale colourScale) { if (m_colourScale == colourScale) return; @@ -487,10 +530,11 @@ m_pixmapCacheInvalid = true; m_colourScale = colourScale; - emit layerParametersChanged(); m_mutex.unlock(); fillCache(); + + emit layerParametersChanged(); } SpectrogramLayer::ColourScale @@ -508,11 +552,21 @@ // don't need to invalidate main cache here m_pixmapCacheInvalid = true; + int formerColourRotation = m_colourRotation; + m_colourScheme = scheme; setCacheColourmap(); + + int distance = formerColourRotation - m_colourRotation; + + if (distance != 0) { + rotateCacheColourmap(-distance); + m_colourRotation = formerColourRotation; + } + + m_mutex.unlock(); + emit layerParametersChanged(); - - m_mutex.unlock(); } SpectrogramLayer::ColourScheme @@ -531,9 +585,10 @@ m_pixmapCacheInvalid = true; m_frequencyScale = frequencyScale; - emit layerParametersChanged(); m_mutex.unlock(); + + emit layerParametersChanged(); } SpectrogramLayer::FrequencyScale @@ -678,21 +733,43 @@ m_cache->setColor (pixel, qRgb(colour.red(), colour.green(), colour.blue())); } + + m_colourRotation = 0; +} + +void +SpectrogramLayer::rotateCacheColourmap(int distance) +{ + QRgb newPixels[256]; + + newPixels[0] = m_cache->color(0); + + for (int pixel = 1; pixel < 256; ++pixel) { + int target = pixel + distance; + while (target < 1) target += 255; + while (target > 255) target -= 255; + newPixels[target] = m_cache->color(pixel); + } + + for (int pixel = 0; pixel < 256; ++pixel) { + m_cache->setColor(pixel, newPixels[pixel]); + } } bool SpectrogramLayer::fillCacheColumn(int column, double *input, fftw_complex *output, fftw_plan plan, + size_t windowSize, + size_t increment, const Window<double> &windower, bool lock) const { - size_t increment = m_windowSize - m_windowSize * m_windowOverlap / 100; int startFrame = increment * column; - int endFrame = startFrame + m_windowSize; + int endFrame = startFrame + windowSize; - startFrame -= int(m_windowSize - increment) / 2; - endFrame -= int(m_windowSize - increment) / 2; + startFrame -= int(windowSize - increment) / 2; + endFrame -= int(windowSize - increment) / 2; size_t pfx = 0; if (startFrame < 0) { @@ -704,13 +781,13 @@ size_t got = m_model->getValues(m_channel, startFrame + pfx, endFrame, input + pfx); - while (got + pfx < m_windowSize) { + while (got + pfx < windowSize) { input[got + pfx] = 0.0; ++got; } if (m_gain != 1.0) { - for (size_t i = 0; i < m_windowSize; ++i) { + for (size_t i = 0; i < windowSize; ++i) { input[i] *= m_gain; } } @@ -722,7 +799,7 @@ if (lock) m_mutex.lock(); bool interrupted = false; - for (size_t i = 0; i < m_windowSize / 2; ++i) { + for (size_t i = 0; i < windowSize / 2; ++i) { int value = 0; @@ -735,7 +812,7 @@ double mag = sqrt(output[i][0] * output[i][0] + output[i][1] * output[i][1]); - mag /= m_windowSize / 2; + mag /= windowSize / 2; switch (m_colourScale) { @@ -804,6 +881,8 @@ size_t start = m_layer.m_model->getStartFrame(); size_t end = m_layer.m_model->getEndFrame(); + + WindowType windowType = m_layer.m_windowType; size_t windowSize = m_layer.m_windowSize; size_t windowIncrement = m_layer.getWindowIncrement(); @@ -822,9 +901,17 @@ } delete m_layer.m_cache; - m_layer.m_cache = new QImage((end - start) / windowIncrement + 1, - windowSize / 2, - QImage::Format_Indexed8); + size_t width = (end - start) / windowIncrement + 1; + size_t height = windowSize / 2; + m_layer.m_cache = new QImage(width, height, + QImage::Format_Indexed8); + + // If we're using JACK in mlock mode, this will be locked + // and we ought to unlock to avoid memory exhaustion. + // Shame it doesn't appear to be possible to allocate + // unlocked in the first place. + //!!! hm, I don't think this is working. + MUNLOCK((void *)m_layer.m_cache, width * height); m_layer.setCacheColourmap(); @@ -840,7 +927,7 @@ fftw_plan plan = fftw_plan_dft_r2c_1d(windowSize, input, output, FFTW_ESTIMATE); - Window<double> windower(m_layer.m_windowType, m_layer.m_windowSize); + Window<double> windower(windowType, windowSize); if (!plan) { std::cerr << "WARNING: fftw_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; @@ -863,7 +950,9 @@ for (size_t f = visibleStart; f < visibleEnd; f += windowIncrement) { m_layer.fillCacheColumn(int((f - start) / windowIncrement), - input, output, plan, windower, false); + input, output, plan, + windowSize, windowIncrement, + windower, false); m_layer.m_mutex.unlock(); m_layer.m_mutex.lock(); @@ -892,7 +981,9 @@ for (size_t f = visibleEnd; f < end; f += windowIncrement) { if (!m_layer.fillCacheColumn(int((f - start) / windowIncrement), - input, output, plan, windower, true)) { + input, output, plan, + windowSize, windowIncrement, + windower, true)) { interrupted = true; m_fillExtent = 0; break; @@ -921,7 +1012,9 @@ for (size_t f = start; f < remainingEnd; f += windowIncrement) { if (!m_layer.fillCacheColumn(int((f - start) / windowIncrement), - input, output, plan, windower, true)) { + input, output, plan, + windowSize, windowIncrement, + windower, true)) { interrupted = true; m_fillExtent = 0; break; @@ -1348,11 +1441,25 @@ } if (divisor > 0.0) { + int pixel = int(total / divisor); if (pixel > 255) pixel = 255; if (pixel < 1) pixel = 1; assert(x <= scaled.width()); scaled.setPixel(x, y, m_cache->color(pixel)); +/* + float pixel = total / divisor; + float lq = pixel - int(pixel); + float hq = int(pixel) + 1 - pixel; + int pixNum = int(pixel); + QRgb low = m_cache->color(pixNum > 255 ? 255 : pixNum); + QRgb high = m_cache->color(pixNum > 254 ? 255 : pixNum + 1); + QRgb mixed = qRgb + (qRed(low) * lq + qRed(high) * hq + 0.01, + qGreen(low) * lq + qGreen(high) * hq + 0.01, + qBlue(low) * lq + qBlue(high) * hq + 0.01); + scaled.setPixel(x, y, mixed); +*/ } else { assert(x <= scaled.width()); scaled.setPixel(x, y, qRgb(0, 0, 0));
--- a/layer/SpectrogramLayer.h Fri Jan 13 18:05:07 2006 +0000 +++ b/layer/SpectrogramLayer.h Mon Jan 16 18:04:09 2006 +0000 @@ -118,6 +118,12 @@ void setColourScheme(ColourScheme scheme); ColourScheme getColourScheme() const; + /** + * Specify the colourmap rotation for the colour scale. + */ + void setColourRotation(int); + int getColourRotation() const; + virtual VerticalPosition getPreferredFrameCountPosition() const { return PositionTop; } @@ -143,6 +149,7 @@ WindowType m_windowType; size_t m_windowOverlap; float m_gain; + int m_colourRotation; size_t m_maxFrequency; ColourScale m_colourScale; ColourScheme m_colourScheme; @@ -184,11 +191,14 @@ bool m_exiting; void setCacheColourmap(); + void rotateCacheColourmap(int distance); bool fillCacheColumn(int column, double *inputBuffer, fftw_complex *outputBuffer, fftw_plan plan, + size_t windowSize, + size_t windowIncrement, const Window<double> &windower, bool lock) const;