Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Spectrum Analyzer #4950

Merged
merged 55 commits into from
Jul 17, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d263bbf
New spectrum analyzer work in progress / init
he29-net Mar 4, 2019
47fba16
Implement resizability and X axis linear/log scale
he29-net Mar 8, 2019
c0563e2
Rework Y axis drawing and add linear scale; various cleanup
he29-net Mar 9, 2019
3e13296
Implement waterfall graph basics; variety of other stuff
he29-net Mar 10, 2019
c71692f
Fix that silly stereo rendering bug; minor waterfall cleanup
he29-net Mar 10, 2019
95e5713
WIP commit before branch switch
he29-net Mar 14, 2019
dcfa7bc
window precomputing update
he29-net Mar 14, 2019
b2ca051
Fix bug with disappearing curves; implement averaging; ref. freeze WIP
he29-net Mar 14, 2019
bbaee49
WIP on FFT block size switching (currently broken)
he29-net Mar 17, 2019
280bd8f
Finished block size and window type switching; many small fixes
he29-net Mar 21, 2019
b80b214
Log scale for waterfall
he29-net Mar 23, 2019
f9f4ef7
WIP on range switching
he29-net Mar 24, 2019
feed0fb
Implemented cursor display and readings for spectrum view
he29-net Mar 24, 2019
66bea0e
Many small improvements, mainly range switching
he29-net Mar 29, 2019
b1b9146
paintEvent rewrite and optimization, peak hold implementation
he29-net Mar 30, 2019
6d1a244
Config GUI overhaul
he29-net Mar 31, 2019
44f1240
Big cleanup in progress
he29-net Mar 31, 2019
d48349b
Continued cleanup; finished waterfall hiding, added zero padding
he29-net Apr 7, 2019
1700b80
Fine-tuning and cleanup done, ready for rebase
he29-net Apr 14, 2019
1decd33
Cleanup of fft_helpers
he29-net Apr 16, 2019
29d89df
Replace std::mutex with QMutex; some additional fine-tuning
he29-net Apr 17, 2019
d6fd391
Fix EffectView mistake; boost gamma curve slightly to make low values…
he29-net May 6, 2019
c7db22a
Update src/core/fft_helpers.cpp
he29-net Jun 1, 2019
134619e
Update src/core/fft_helpers.cpp
he29-net Jun 1, 2019
8ef716a
fft_helpers.h indentation fix
he29-net Jun 1, 2019
5e07a28
fft_helpers: Add @return tags to function commets; mark pointer and r…
he29-net Jun 1, 2019
ba85822
Move opening brackets to separate line
he29-net Jun 1, 2019
9e40dc4
Fix Doxygen syntax in fft_helpers
he29-net Jun 1, 2019
2b59149
Fix of the previous 'Doxygen fix' fix
he29-net Jun 2, 2019
0058626
Add tool-tips
he29-net Jun 2, 2019
b03d48d
Update plugins/SpectrumAnalyzer/SaProcessor.h
he29-net Jun 14, 2019
5f18863
Update plugins/SpectrumAnalyzer/Analyzer.h
he29-net Jun 14, 2019
cec0768
Update plugins/SpectrumAnalyzer/SaProcessor.cpp
he29-net Jun 14, 2019
b9d3e0d
Update plugins/SpectrumAnalyzer/SaControlsDialog.cpp
he29-net Jun 14, 2019
70b964c
Update plugins/SpectrumAnalyzer/SaControlsDialog.h
he29-net Jun 14, 2019
def85bc
Update plugins/SpectrumAnalyzer/SaSpectrumView.h
he29-net Jun 14, 2019
57a5b6e
Remove EffectControlDialog pointer from SaControls, add a replacement…
he29-net Jun 14, 2019
8c5c35a
Use markdown syntax for readme file
he29-net Jun 14, 2019
4431e6e
Fix the markdown syntax I just added xD
he29-net Jun 14, 2019
86f01ff
... and change changelog formatting, since apparently tabs here are 8…
he29-net Jun 14, 2019
d0a7f70
Arrgh! And fix a typo in the title >_<
he29-net Jun 14, 2019
78d328e
Avoid waterfall history updates when there is no input
he29-net Jun 15, 2019
be824e1
Display black rectangle instead waterfall when no data are available
he29-net Jun 15, 2019
0e6aa9e
Add 'override's to overriding methods; mark additional constructors a…
he29-net Jun 15, 2019
aa41b84
Remove iostream include from SaWaterfall
he29-net Jun 16, 2019
1556187
Update plugins/SpectrumAnalyzer/SaProcessor.cpp
he29-net Jun 23, 2019
ec9615c
Update plugins/SpectrumAnalyzer/SaProcessor.cpp
he29-net Jun 23, 2019
ff13ca3
Update plugins/SpectrumAnalyzer/SaProcessor.cpp
he29-net Jun 23, 2019
217f629
Update plugins/SpectrumAnalyzer/SaProcessor.cpp
he29-net Jun 23, 2019
b359881
First batch of changes for second review round
he29-net Jun 23, 2019
f4510ec
Make some -Weverything warnings go away (mainly implicit signed vs. u…
he29-net Jun 26, 2019
c8a105c
Cleanup includes, update comments in SaProcessor
he29-net Jun 26, 2019
89d4703
Batch of changes for the third review
he29-net Jul 11, 2019
14e9008
Restrict cursor drawing to graph ranges
JohannesLorenz Jul 14, 2019
1409f1f
Spectrum View: Use existing cursor boundaries
JohannesLorenz Jul 16, 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
2 changes: 2 additions & 0 deletions include/EffectControlDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class LMMS_EXPORT EffectControlDialog : public QWidget, public ModelView
EffectControlDialog( EffectControls * _controls );
virtual ~EffectControlDialog();

virtual bool isResizable() const {return false;}


signals:
void closed();
Expand Down
79 changes: 56 additions & 23 deletions include/fft_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* fft_helpers.h - some functions around FFT analysis
*
* Copyright (c) 2008-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2019 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
Expand All @@ -28,44 +29,75 @@

#include "lmms_export.h"

#include <vector>
#include <fftw3.h>

// NOTE: FFT_BUFFER_SIZE should be considered deprecated!
// It is used by Eq plugin and some older code here, but this should be a user
// switchable parameter, not a constant. Use a value from FFT_BLOCK_SIZES
const int FFT_BUFFER_SIZE = 2048;

enum WINDOWS
{
KAISER=1,
RECTANGLE,
HANNING,
HAMMING
// Allowed FFT block sizes. Ranging from barely useful to barely acceptable
// because of performance reasons.
const std::vector<int> FFT_BLOCK_SIZES = {256, 512, 1024, 2048, 4096, 8192, 16384};

// List of FFT window functions supported by precomputeWindow()
enum FFT_WINDOWS {
he29-net marked this conversation as resolved.
Show resolved Hide resolved
RECTANGULAR = 0,
he29-net marked this conversation as resolved.
Show resolved Hide resolved
BLACKMAN_HARRIS,
HAMMING,
HANNING
};

/* returns biggest value from abs_spectrum[spec_size] array

/* Returns biggest value from abs_spectrum[spec_size] array.
he29-net marked this conversation as resolved.
Show resolved Hide resolved
*
* returns -1 on error
*/
float LMMS_EXPORT maximum(float *abs_spectrum, unsigned int spec_size);
float LMMS_EXPORT maximum(std::vector<float> &abs_spectrum);


/* Normalize the abs_spectrum array of absolute values to a 0..1 range
* based on supplied energy and stores it in the norm_spectrum array.
*
* returns -1 on error
*/
int LMMS_EXPORT normalize(float *abs_spectrum, float *norm_spectrum, unsigned int bin_count, unsigned int block_size);
int LMMS_EXPORT normalize(std::vector<float> &abs_spectrum, std::vector<float> &norm_spectrum, unsigned int block_size);


/* Check if the spectrum contains any non-zero value.
*
* returns -1 on error
* returns 1 if spectrum contains any non-zero value
* returns 0 otherwise
*/
float LMMS_EXPORT maximum( float * _abs_spectrum, unsigned int _spec_size );
int LMMS_EXPORT notEmpty(std::vector<float> &spectrum);


/* apply hanning or hamming window to channel
/* Precompute a window function for later real-time use.
* Set normalized to false if you do not want to apply amplitude correction.
*
* returns -1 on error
* returns -1 on error
*/
int LMMS_EXPORT hanming( float * _timebuffer, int _length, WINDOWS _type );
int LMMS_EXPORT precomputeWindow(float *window, int length, FFT_WINDOWS type, bool normalized = true);

/* compute absolute values of complex_buffer, save to absspec_buffer
* take care that - compl_len is not bigger than complex_buffer!
* - absspec buffer is big enough!

/* Compute absolute values of complex_buffer, save to absspec_buffer.
* Take care that - compl_len is not bigger than complex_buffer!
* - absspec buffer is big enough!
*
* returns 0 on success, else -1
* returns 0 on success, else -1
*/
int LMMS_EXPORT absspec( fftwf_complex * _complex_buffer, float * _absspec_buffer,
int _compl_length );
int LMMS_EXPORT absspec(fftwf_complex *complex_buffer, float *absspec_buffer,
int compl_length);


/* build fewer subbands from many absolute spectrum values
* take care that - compressedbands[] array num_new elements long
* - num_old > num_new
/* Build fewer subbands from many absolute spectrum values.
* Take care that - compressedbands[] array num_new elements long
* - num_old > num_new
*
* returns 0 on success, else -1
* returns 0 on success, else -1
*/
int LMMS_EXPORT compressbands( float * _absspec_buffer, float * _compressedband,
int _num_old, int _num_new, int _bottom, int _top );
Expand All @@ -74,10 +106,11 @@ int LMMS_EXPORT compressbands( float * _absspec_buffer, float * _compressedband,
int LMMS_EXPORT calc13octaveband31( float * _absspec_buffer, float * _subbands,
int _num_spec, float _max_frequency );


/* compute power of finite time sequence
* take care num_values is length of timesignal[]
*
* returns power on success, else -1
* returns power on success, else -1
*/
float LMMS_EXPORT signalpower(float *timesignal, int num_values);

Expand Down
76 changes: 76 additions & 0 deletions plugins/SpectrumAnalyzer/Analyzer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Analyzer.cpp - definition of Analyzer class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014-2017, David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#include "Analyzer.h"

#include "embed.h"
#include "plugin_export.h"


extern "C" {
Plugin::Descriptor PLUGIN_EXPORT analyzer_plugin_descriptor =
{
STRINGIFY(PLUGIN_NAME),
"Spectrum Analyzer",
QT_TRANSLATE_NOOP("pluginBrowser", "A graphical spectrum analyzer."),
"Martin Pavelek <he29/dot/HS/at/gmail/dot/com>",
0x0100,
Plugin::Effect,
new PluginPixmapLoader("logo"),
NULL,
NULL
};
}


Analyzer::Analyzer(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) :
Effect(&analyzer_plugin_descriptor, parent, key),
m_controls(this),
m_processor(&m_controls)
{
}


// Take audio data and pass them to the spectrum processor.
// Skip processing if the controls dialog isn't visible, it would only waste CPU cycles.
bool Analyzer::processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count) {
if (!isEnabled() || !isRunning ()) {
return false;
}
if (m_controls.isViewVisible()) {
m_processor.analyse(buffer, frame_count);
}
return isRunning();
JohannesLorenz marked this conversation as resolved.
Show resolved Hide resolved
}


extern "C" {
// needed for getting plugin out of shared lib
PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *parent, void *data) {
return new Analyzer(parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(data));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/*
* SpectrumAnalyzerControlDialog.h - view for spectrum analyzer
/* Analyzer.h - declaration of Analyzer class.
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014-2017, David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
Expand All @@ -22,32 +24,27 @@
*
*/

#ifndef _SPECTRUM_ANALYZER_CONTROL_DIALOG_H
#define _SPECTRUM_ANALYZER_CONTROL_DIALOG_H

#include "EffectControlDialog.h"
#ifndef ANALYZER_H
#define ANALYZER_H

#include "Effect.h"
#include "SaControls.h"
#include "SaProcessor.h"

class SpectrumAnalyzerControls;


class SpectrumAnalyzerControlDialog : public EffectControlDialog
{
Q_OBJECT
// Top level class; handles LMMS interface and feeds data to the data processor.
he29-net marked this conversation as resolved.
Show resolved Hide resolved
class Analyzer : public Effect {
public:
SpectrumAnalyzerControlDialog( SpectrumAnalyzerControls* controls );
virtual ~SpectrumAnalyzerControlDialog()
{
}
Analyzer(Model *parent, const Descriptor::SubPluginFeatures::Key *key);
virtual ~Analyzer() {};

private:
virtual void paintEvent( QPaintEvent* event );
virtual bool processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count);
virtual EffectControls *controls() {return &m_controls;}
SaProcessor *getProcessor() {return &m_processor;}

SpectrumAnalyzerControls* m_controls;

QPixmap m_logXAxis;
QPixmap m_logYAxis;

} ;
private:
SaControls m_controls;
SaProcessor m_processor;
};

#endif
#endif // ANALYZER_H
3 changes: 2 additions & 1 deletion plugins/SpectrumAnalyzer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
INCLUDE(BuildPlugin)
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
LINK_LIBRARIES(${FFTW3F_LIBRARIES})
BUILD_PLUGIN(spectrumanalyzer SpectrumAnalyzer.cpp SpectrumAnalyzerControls.cpp SpectrumAnalyzerControlDialog.cpp SpectrumAnalyzer.h SpectrumAnalyzerControls.h SpectrumAnalyzerControlDialog.h MOCFILES SpectrumAnalyzerControlDialog.h SpectrumAnalyzerControls.h EMBEDDED_RESOURCES *.png)
BUILD_PLUGIN(analyzer Analyzer.cpp SaProcessor.cpp SaControls.cpp SaControlsDialog.cpp SaSpectrumView.cpp SaWaterfallView.cpp
MOCFILES SaProcessor.h SaControls.h SaControlsDialog.h SaSpectrumView.h SaWaterfallView.h EMBEDDED_RESOURCES *.svg logo.png)
13 changes: 13 additions & 0 deletions plugins/SpectrumAnalyzer/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Overview
he29-net marked this conversation as resolved.
Show resolved Hide resolved
--------

This plugin consists of three widgets and back-end code to provide them with required data.

The top-level widget is SaControlDialog. It populates a configuration widget (created dynamically) and instantiates spectrum display widgets. Its main back-end class is SaControls, which holds all configuration values and globally valid constants (e.g. range definitions).

SaSpectrumDisplay and SaWaterfallDisplay show the result of spectrum analysis. Their main back-end class is SaProcessor, which performs FFT analysis on data received from the Analyzer class, which in turn handles the interface with LMMS.


Changelog
---------
1.0.0 2019-04-07 Initial release
Loading