Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9be31e0
tweak amplitude ranges, update and fix readme.md
he29-net Jul 21, 2019
4e2f168
Add and implement advanced settings
he29-net Aug 15, 2019
f5eda87
Display waterfall at native resolution
he29-net Aug 23, 2019
7d630e1
Add waterfall cursor, fix time labels and make density change with wi…
he29-net Aug 23, 2019
249d161
Fix normalization so that full scale sinewave is 0 dBFS; tweak perf. …
he29-net Aug 23, 2019
25aa537
Move FFT analysis to a separate thread for better performance and rea…
he29-net Aug 23, 2019
3707eeb
Performance optimizations and some final touches here and there
he29-net Sep 1, 2019
cb3e701
Improve cursor coordinates display
he29-net Sep 1, 2019
8d639e5
Fix missed transient in the first block despite having overlapping en…
he29-net Sep 16, 2019
36feb65
workaround for QMouseEvent::localPos() bug
he29-net Oct 8, 2019
b650838
Update plugins/SpectrumAnalyzer/SaSpectrumView.cpp
he29-net Oct 13, 2019
42d74db
Make SaProcessor unfriendly to view classes
he29-net Oct 13, 2019
9dd9ef0
Update and improve readme file; use consistent "analyzer" spelling
he29-net Oct 13, 2019
6a5089d
Use QString directly where possible
he29-net Oct 13, 2019
6939702
Fix bug introduced in previous commit
he29-net Oct 13, 2019
11013cc
SaProcessor: make some variables accessed by other classes atomic; ma…
he29-net Oct 17, 2019
edefc93
test a change required to make analyzer work after make install
he29-net Oct 24, 2019
e3c89d5
Build the ringbuffer libary as part of LMMS core
he29-net Oct 28, 2019
5b1f28c
Attempted fix of missing ringbuffer.cpp symbols on Win platforms
he29-net Oct 30, 2019
7cf189c
Move most ringbuffer cmake setup to 3rdparty/, hijack RINGBUFFER_EXPO…
he29-net Oct 30, 2019
11bb2c7
Add LMMS_EXPORT to LocklessRingBuffer methods
he29-net Nov 7, 2019
2963fb6
Revert "Add LMMS_EXPORT to LocklessRingBuffer methods"
PhysSong Nov 7, 2019
6dd2619
Try to fix an export error
PhysSong Nov 7, 2019
6856b3d
Rework LocklessRingBuffer and force export of <sampleFrame> template …
he29-net Nov 9, 2019
0d56ae8
Move <sampleFrame> instances to the bottom of file
he29-net Nov 9, 2019
228dd2f
Revert "Move <sampleFrame> instances to the bottom of file"
he29-net Nov 9, 2019
22e9163
Move specialized write() above the non-specialized one
he29-net Nov 9, 2019
dc2bd91
Move sampleFrame instantiation to the header file
he29-net Nov 9, 2019
8739abb
Try to remove LMMS_EXPORT from LocklessRingBuffer template
he29-net Nov 14, 2019
7a0fc5a
Go back to 'everything in the header' to fix Mac and hope it does not…
he29-net Nov 14, 2019
bf793da
Try removing all LMMS_EXPORTs from LocklessRingBuffer
he29-net Nov 15, 2019
ad49d36
Merge remote-tracking branch 'upstream/master' into analyzer-update
he29-net Nov 15, 2019
a0acc8a
Implement LocklessRingBuffer changes requested in review
he29-net Nov 16, 2019
8ca05a3
Fix code conventions, make some includes harder to read
he29-net Nov 17, 2019
c694277
Forgotten rename
he29-net Nov 17, 2019
0caa748
Fix missing part of waterfall when its width limit is reached
he29-net Nov 18, 2019
a7388b1
Fix drawing bounds of "overload fill-in"; improve comment on waterfal…
he29-net Nov 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make SaProcessor unfriendly to view classes
  • Loading branch information
he29-net committed Oct 13, 2019
commit 42d74db553eea6005d98366be3a1dc266e11ee41
15 changes: 15 additions & 0 deletions plugins/SpectrumAnalyzer/SaProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,21 @@ void SaProcessor::clear()
std::fill(m_history.begin(), m_history.end(), 0);
}

// Clear only history work buffer. Used to flush old data when waterfall
// is shown after a period of inactivity.
void SaProcessor::clearHistory()
{
QMutexLocker lock(&m_dataAccess);
std::fill(m_history_work.begin(), m_history_work.end(), 0);
}

// Check if result buffers contain any non-zero values
bool SaProcessor::spectrumNotEmpty()
{
QMutexLocker lock(&m_reallocationAccess);
return notEmpty(m_normSpectrumL) || notEmpty(m_normSpectrumR);
}


// --------------------------------------
// Frequency conversion helpers
Expand Down
21 changes: 14 additions & 7 deletions plugins/SpectrumAnalyzer/SaProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,21 @@ class SaProcessor
void reallocateBuffers();
void rebuildWindow();
void clear();
Comment thread
JohannesLorenz marked this conversation as resolved.
void clearHistory();

const float *getSpectrumL() const {return m_normSpectrumL.data();}
const float *getSpectrumR() const {return m_normSpectrumR.data();}
const uchar *getHistory() const {return m_history.data();}

// information about results and unit conversion helpers
const unsigned int &inBlockSize() const {return m_inBlockSize;}
Comment thread
he29-net marked this conversation as resolved.
Outdated
unsigned int binCount() const; //!< size of output (frequency domain) data block
bool spectrumNotEmpty(); //!< check if result buffers contain any non-zero values

unsigned int waterfallWidth() const; //!< binCount value capped at 3840 (for display)
const unsigned int& waterfallHeight() const {return m_waterfallHeight;}
bool waterfallNotEmpty() const {return m_waterfallNotEmpty;}

float binToFreq(unsigned int bin_index) const;
float binBandwidth() const;

Expand Down Expand Up @@ -103,8 +116,6 @@ class SaProcessor
unsigned int m_fftBlockSize; //!< size of padded block for FFT processing
unsigned int m_sampleRate;

unsigned int binCount() const; //!< size of output (frequency domain) data block

// data buffers (roughly in the order of processing, from input to output)
unsigned int m_framesFilledUp;
std::vector<float> m_bufferL; //!< time domain samples (left)
Expand All @@ -128,20 +139,16 @@ class SaProcessor
unsigned int m_waterfallHeight; //!< number of stored lines in history buffer
Comment thread
he29-net marked this conversation as resolved.
Outdated
// Note: high values may make it harder to see transients.
const unsigned int m_waterfallMaxWidth = 3840;
unsigned int waterfallWidth() const; //!< binCount value capped at 3840 (for display)

// book keeping
bool m_spectrumActive;
bool m_waterfallActive;
unsigned int m_waterfallNotEmpty;
unsigned int m_waterfallNotEmpty; //!< number of lines remaining visible on display
bool m_reallocating;

// merge L and R channels and apply gamma correction to make a spectrogram pixel
QRgb makePixel(float left, float right) const;

friend class SaSpectrumView;
friend class SaWaterfallView;

#ifdef SA_DEBUG
unsigned int m_last_dump_time;
unsigned int m_dump_count;
Expand Down
14 changes: 4 additions & 10 deletions plugins/SpectrumAnalyzer/SaSpectrumView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,8 @@ void SaSpectrumView::drawSpectrum(QPainter &painter)
#endif

// draw the graph only if there is any input, averaging residue or peaks
QMutexLocker lock(&m_processor->m_reallocationAccess);
if (m_decaySum > 0 || notEmpty(m_processor->m_normSpectrumL) || notEmpty(m_processor->m_normSpectrumR))
if (m_decaySum > 0 || m_processor->spectrumNotEmpty())
{
lock.unlock();
// update data buffers and reconstruct paths
refreshPaths();

Expand Down Expand Up @@ -204,10 +202,6 @@ void SaSpectrumView::drawSpectrum(QPainter &painter)
draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - draw_time;
#endif
}
else
{
lock.unlock();
}

#ifdef SA_DEBUG
// save performance measurement result
Expand Down Expand Up @@ -242,8 +236,8 @@ void SaSpectrumView::refreshPaths()
int refresh_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
m_decaySum = 0;
updateBuffers(m_processor->m_normSpectrumL.data(), m_displayBufferL.data(), m_peakBufferL.data());
updateBuffers(m_processor->m_normSpectrumR.data(), m_displayBufferR.data(), m_peakBufferR.data());
updateBuffers(m_processor->getSpectrumL(), m_displayBufferL.data(), m_peakBufferL.data());
updateBuffers(m_processor->getSpectrumR(), m_displayBufferR.data(), m_peakBufferR.data());
#ifdef SA_DEBUG
refresh_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - refresh_time;
#endif
Expand Down Expand Up @@ -292,7 +286,7 @@ void SaSpectrumView::refreshPaths()
// reallocation access lock! Data access lock is not needed: the final result
// buffer is updated very quickly and the worst case is that one frame will be
// part new, part old. At reasonable frame rate, such difference is invisible..
void SaSpectrumView::updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer)
void SaSpectrumView::updateBuffers(const float *spectrum, float *displayBuffer, float *peakBuffer)
{
for (int n = 0; n < m_processor->binCount(); n++)
{
Expand Down
2 changes: 1 addition & 1 deletion plugins/SpectrumAnalyzer/SaSpectrumView.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private slots:
std::vector<float> m_displayBufferR;
std::vector<float> m_peakBufferL;
std::vector<float> m_peakBufferR;
void updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer);
void updateBuffers(const float *spectrum, float *displayBuffer, float *peakBuffer);

// final paths to be drawn by QPainter and methods to build them
QPainterPath m_pathL;
Expand Down
21 changes: 9 additions & 12 deletions plugins/SpectrumAnalyzer/SaWaterfallView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ void SaWaterfallView::paintEvent(QPaintEvent *event)
painter.setRenderHint(QPainter::Antialiasing, true);

// check if time labels need to be rebuilt
if (secondsPerLine() != m_oldSecondsPerLine || m_processor->m_waterfallHeight != m_oldHeight)
if (secondsPerLine() != m_oldSecondsPerLine || m_processor->waterfallHeight() != m_oldHeight)
{
m_timeTics = makeTimeTics();
m_oldSecondsPerLine = secondsPerLine();
m_oldHeight = m_processor->m_waterfallHeight;
m_oldHeight = m_processor->waterfallHeight();
}

// print time labels
Expand Down Expand Up @@ -137,12 +137,12 @@ void SaWaterfallView::paintEvent(QPaintEvent *event)
}

// draw the spectrogram precomputed in SaProcessor
if (m_processor->m_waterfallNotEmpty)
if (m_processor->waterfallNotEmpty())
Comment thread
he29-net marked this conversation as resolved.
{
QMutexLocker lock(&m_processor->m_reallocationAccess);
QImage temp = QImage(m_processor->m_history.data(), // raw pixel data to display
QImage temp = QImage(m_processor->getHistory(), // raw pixel data to display
m_processor->waterfallWidth(), // width = number of frequency bins
m_processor->m_waterfallHeight, // height = number of history lines
m_processor->waterfallHeight(), // height = number of history lines
QImage::Format_RGB32);
lock.unlock();
temp.setDevicePixelRatio(devicePixelRatio()); // display at native resolution
Expand Down Expand Up @@ -178,7 +178,7 @@ void SaWaterfallView::paintEvent(QPaintEvent *event)
// Helper functions for time conversion
float SaWaterfallView::samplesPerLine()
{
return (float)m_processor->m_inBlockSize / m_controls->m_windowOverlapModel.value();
return (float)m_processor->inBlockSize() / m_controls->m_windowOverlapModel.value();
}

float SaWaterfallView::secondsPerLine()
Comment thread
JohannesLorenz marked this conversation as resolved.
Expand All @@ -190,7 +190,7 @@ float SaWaterfallView::secondsPerLine()
// Convert time value to Y coordinate for display of given height.
float SaWaterfallView::timeToYPixel(float time, int height)
{
float pixels_per_line = (float)height / m_processor->m_waterfallHeight;
float pixels_per_line = (float)height / m_processor->waterfallHeight();

return pixels_per_line * time / secondsPerLine();
}
Expand All @@ -200,7 +200,7 @@ float SaWaterfallView::timeToYPixel(float time, int height)
float SaWaterfallView::yPixelToTime(float position, int height)
{
if (height == 0) {height = 1;}
float pixels_per_line = (float)height / m_processor->m_waterfallHeight;
float pixels_per_line = (float)height / m_processor->waterfallHeight();

return (position / pixels_per_line) * secondsPerLine();
}
Expand Down Expand Up @@ -258,10 +258,7 @@ void SaWaterfallView::updateVisibility()
if (m_controls->m_waterfallModel.value())
{
// clear old data before showing the waterfall
QMutexLocker lock(&m_processor->m_dataAccess);
std::fill(m_processor->m_history_work.begin(), m_processor->m_history_work.end(), 0);
lock.unlock();

m_processor->clearHistory();
setVisible(true);

// increase window size if it is too small
Expand Down