Merge pull request #11 from LMMS/master

Master
This commit is contained in:
Lost Robot
2019-08-07 08:29:09 -06:00
committed by GitHub
119 changed files with 58999 additions and 11006 deletions

5
.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
root = true
[*]
indent_style = tab
tab_width = 4

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
custom: https://lmms.io/get-involved/#donate

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

View File

@@ -68,7 +68,7 @@ public:
virtual PluginView * instantiateView( QWidget * _parent )
{
return new InstrumentView( this, _parent );
return new InstrumentViewFixedSize( this, _parent );
}
} ;

View File

@@ -40,6 +40,8 @@ public:
EffectControlDialog( EffectControls * _controls );
virtual ~EffectControlDialog();
virtual bool isResizable() const {return false;}
signals:
void closed();

View File

@@ -35,8 +35,10 @@ class FadeButton : public QAbstractButton
{
Q_OBJECT
public:
FadeButton( const QColor & _normal_color, const QColor &
_activated_color, QWidget * _parent );
FadeButton( const QColor & _normal_color,
const QColor & _activated_color,
const QColor & _hold_color,
QWidget * _parent );
virtual ~FadeButton();
void setActiveColor( const QColor & activated_color );
@@ -44,6 +46,7 @@ public:
public slots:
void activate();
void noteEnd();
protected:
@@ -53,13 +56,20 @@ protected:
private:
QTime m_stateTimer;
QTime m_releaseTimer;
// the default color of the widget
QColor m_normalColor;
// the color on note play
QColor m_activatedColor;
// the color after the "play" fade is done but a note is still playing
QColor m_holdColor;
int activeNotes;
void signalUpdate();
QColor fadeToColor(QColor, QColor, QTime, float);
} ;
#endif

View File

@@ -79,8 +79,6 @@ public:
static const int FxLineHeight;
void renameChannel();
bool eventFilter (QObject *dist, QEvent *event);
private:
@@ -101,6 +99,9 @@ private:
QLineEdit * m_renameLineEdit;
QGraphicsView * m_view;
public slots:
void renameChannel();
private slots:
void renameFinished();
void removeChannel();

View File

@@ -221,6 +221,7 @@ signals:
void midiNoteOff( const Note& );
void nameChanged();
void newNote();
void endNote();
protected:

View File

@@ -32,11 +32,12 @@
class InstrumentTrackWindow;
//! Instrument view with variable size
class LMMS_EXPORT InstrumentView : public PluginView
{
public:
InstrumentView( Instrument * _instrument, QWidget * _parent );
virtual ~InstrumentView();
~InstrumentView() override;
Instrument * model()
{
@@ -48,11 +49,25 @@ public:
return( castModel<Instrument>() );
}
virtual void setModel( Model * _model, bool = false );
void setModel( Model * _model, bool = false ) override;
InstrumentTrackWindow * instrumentTrackWindow();
} ;
//! Instrument view with fixed LMMS-default size
class LMMS_EXPORT InstrumentViewFixedSize : public InstrumentView
{
QSize sizeHint() const override { return QSize(250, 250); }
QSize minimumSizeHint() const override { return sizeHint(); }
public:
using InstrumentView::InstrumentView;
~InstrumentViewFixedSize() override;
} ;
#endif

View File

@@ -63,7 +63,7 @@ public:
MidiTime( const tact_t tact, const tick_t ticks );
MidiTime( const tick_t ticks = 0 );
MidiTime toNearestTact() const;
MidiTime quantize(float) const;
MidiTime toAbsoluteTact() const;
MidiTime& operator+=( const MidiTime& time );
@@ -110,4 +110,3 @@ private:
#endif

View File

@@ -315,6 +315,7 @@ public:
inline bool isMetronomeActive() const { return m_metronomeActive; }
inline void setMetronomeActive(bool value = true) { m_metronomeActive = value; }
//! Block until a change in model can be done (i.e. wait for audio thread)
void requestChangeInModel();
void doneChangeInModel();
@@ -366,6 +367,8 @@ private:
void clearInternal();
//! Called by the audio thread to give control to other threads,
//! such that they can do changes in the model (like e.g. removing effects)
void runChangesInModel();
bool m_renderOnly;

View File

@@ -139,7 +139,7 @@ public:
virtual bool play( const MidiTime & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 );
virtual TrackView * createView( TrackContainerView* tcv );
virtual TrackContentObject * createTCO( const MidiTime & _pos );
virtual TrackContentObject * createTCO(const MidiTime & pos);
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
@@ -218,6 +218,8 @@ protected:
return "SampleTrackView";
}
void dragEnterEvent(QDragEnterEvent *dee);
void dropEvent(QDropEvent *de);
private slots:
void assignFxLine( int channelIndex );

View File

@@ -73,6 +73,9 @@ public:
void loadSettings( const QDomElement& element );
ComboBoxModel *zoomingModel() const;
ComboBoxModel *snappingModel() const;
float getSnapSize() const;
QString getSnapSizeString() const;
public slots:
void scrolled( int new_pos );
@@ -80,6 +83,7 @@ public slots:
void setEditMode( EditMode mode );
void setEditModeDraw();
void setEditModeSelect();
void toggleProportionalSnap();
void updatePosition( const MidiTime & t );
void updatePositionLine();
@@ -130,6 +134,8 @@ private:
positionLine * m_positionLine;
ComboBoxModel* m_zoomingModel;
ComboBoxModel* m_snappingModel;
bool m_proportionalSnap;
static const QVector<double> m_zoomLevels;
@@ -141,7 +147,6 @@ private:
EditMode m_ctrlMode; // mode they were in before they hit ctrl
friend class SongEditorWindow;
} ;
@@ -170,6 +175,8 @@ protected slots:
void lostFocus();
void adjustUiAfterProjectLoad();
void updateSnapLabel();
signals:
void playTriggered();
void resized();
@@ -181,6 +188,7 @@ private:
QAction* m_addBBTrackAction;
QAction* m_addSampleTrackAction;
QAction* m_addAutomationTrackAction;
QAction* m_setProportionalSnapAction;
ActionGroup * m_editModeGroup;
QAction* m_drawModeAction;
@@ -188,6 +196,8 @@ private:
QAction* m_crtlAction;
ComboBox * m_zoomingComboBox;
ComboBox * m_snappingComboBox;
QLabel* m_snapSizeLabel;
};
#endif

View File

@@ -30,7 +30,6 @@
#include <QGraphicsDropShadowEffect>
#include <QMdiSubWindow>
#include <QLabel>
#include <QPainter>
#include <QPushButton>
#include <QString>

View File

@@ -78,6 +78,7 @@ protected:
virtual void resizeEvent( QResizeEvent * _re );
virtual void wheelEvent( QWheelEvent * _we );
virtual QSize minimumSizeHint() const;
virtual QSize sizeHint() const;
private:
struct widgetDesc

View File

@@ -236,7 +236,7 @@ public:
// access needsUpdate member variable
bool needsUpdate();
void setNeedsUpdate( bool b );
public slots:
virtual bool close();
void cut();
@@ -297,6 +297,9 @@ private:
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
MidiTime m_initialTCOPos;
MidiTime m_initialTCOEnd;
QVector<MidiTime> m_initialOffsets;
TextFloat * m_hint;
@@ -311,14 +314,17 @@ private:
bool m_gradient;
bool m_needsUpdate;
inline void setInitialMousePos( QPoint pos )
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialTCOPos = m_tco->startPosition();
m_initialTCOEnd = m_initialTCOPos + m_tco->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
MidiTime draggedTCOPos( QMouseEvent * me );
} ;
@@ -564,13 +570,13 @@ public:
using Model::dataChanged;
inline int getHeight()
inline int getHeight()
{
return m_height >= MINIMAL_TRACK_HEIGHT
? m_height
? m_height
: DEFAULT_TRACK_HEIGHT;
}
inline void setHeight( int height )
inline void setHeight( int height )
{
m_height = height;
}

View File

@@ -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
*
@@ -28,57 +29,90 @@
#include "lmms_export.h"
#include <vector>
#include <fftw3.h>
const int FFT_BUFFER_SIZE = 2048;
// 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 unsigned int FFT_BUFFER_SIZE = 2048;
enum WINDOWS
// Allowed FFT block sizes. Ranging from barely useful to barely acceptable
// because of performance and latency reasons.
const std::vector<unsigned int> FFT_BLOCK_SIZES = {256, 512, 1024, 2048, 4096, 8192, 16384};
// List of FFT window functions supported by precomputeWindow()
enum FFT_WINDOWS
{
KAISER=1,
RECTANGLE,
HANNING,
HAMMING
RECTANGULAR = 0,
BLACKMAN_HARRIS,
HAMMING,
HANNING
};
/* returns biggest value from abs_spectrum[spec_size] array
/** Returns biggest value from abs_spectrum[spec_size] array.
*
* returns -1 on error
* @return -1 on error, 0 on success
*/
float LMMS_EXPORT maximum( float * _abs_spectrum, unsigned int _spec_size );
float LMMS_EXPORT maximum(const float *abs_spectrum, unsigned int spec_size);
float LMMS_EXPORT maximum(const std::vector<float> &abs_spectrum);
/* apply hanning or hamming window to channel
/** 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
* @return -1 on error
*/
int LMMS_EXPORT hanming( float * _timebuffer, int _length, WINDOWS _type );
int LMMS_EXPORT normalize(const float *abs_spectrum, float *norm_spectrum, unsigned int bin_count, unsigned int block_size);
int LMMS_EXPORT normalize(const std::vector<float> &abs_spectrum, std::vector<float> &norm_spectrum, unsigned int block_size);
/* 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!
/** Check if the spectrum contains any non-zero value.
*
* returns 0 on success, else -1
* @return 1 if spectrum contains any non-zero value
* @return 0 otherwise
*/
int LMMS_EXPORT absspec( fftwf_complex * _complex_buffer, float * _absspec_buffer,
int _compl_length );
int LMMS_EXPORT notEmpty(const std::vector<float> &spectrum);
/* build fewer subbands from many absolute spectrum values
* take care that - compressedbands[] array num_new elements long
* - num_old > num_new
/** Precompute a window function for later real-time use.
* Set normalized to false if you do not want to apply amplitude correction.
*
* returns 0 on success, else -1
* @return -1 on error
*/
int LMMS_EXPORT compressbands( float * _absspec_buffer, float * _compressedband,
int _num_old, int _num_new, int _bottom, int _top );
int LMMS_EXPORT precomputeWindow(float *window, unsigned int length, FFT_WINDOWS type, bool normalized = true);
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[]
/** 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 power on success, else -1
* @return 0 on success, else -1
*/
float LMMS_EXPORT signalpower(float *timesignal, int num_values);
int LMMS_EXPORT absspec(const fftwf_complex *complex_buffer, float *absspec_buffer,
unsigned int compl_length);
/** Build fewer subbands from many absolute spectrum values.
* Take care that - compressedbands[] array num_new elements long
* - num_old > num_new
*
* @return 0 on success, else -1
*/
int LMMS_EXPORT compressbands(const float * _absspec_buffer, float * _compressedband,
int _num_old, int _num_new, int _bottom, int _top);
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[].
*
* @return power on success, else -1
*/
float LMMS_EXPORT signalpower(const float *timesignal, int num_values);
#endif

View File

@@ -457,7 +457,7 @@ public:
FreeBoyInstrumentView::FreeBoyInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );

View File

@@ -111,7 +111,7 @@ private:
} ;
class FreeBoyInstrumentView : public InstrumentView
class FreeBoyInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -922,7 +922,7 @@ public:
GigInstrumentView::GigInstrumentView( Instrument * _instrument, QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
GigInstrument * k = castModel<GigInstrument>();

View File

@@ -334,7 +334,7 @@ signals:
class GigInstrumentView : public InstrumentView
class GigInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -681,7 +681,7 @@ void OpulenzInstrument::loadFile( const QString& file ) {
OpulenzInstrumentView::OpulenzInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
#define KNOB_GEN(knobname, hinttext, hintunit,xpos,ypos) \

View File

@@ -142,7 +142,7 @@ private:
class OpulenzInstrumentView : public InstrumentView
class OpulenzInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -0,0 +1,75 @@
/*
* 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 =
{
"spectrumanalyzer",
"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_processor(&m_controls),
m_controls(this)
{
}
// 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();
}
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));
}
}

View File

@@ -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
*
@@ -22,32 +24,30 @@
*
*/
#ifndef _SPECTRUM_ANALYZER_CONTROL_DIALOG_H
#define _SPECTRUM_ANALYZER_CONTROL_DIALOG_H
#ifndef ANALYZER_H
#define ANALYZER_H
#include "EffectControlDialog.h"
#include "Effect.h"
#include "SaControls.h"
#include "SaProcessor.h"
class SpectrumAnalyzerControls;
class SpectrumAnalyzerControlDialog : public EffectControlDialog
//! Top level class; handles LMMS interface and feeds data to the data processor.
class Analyzer : public Effect
{
Q_OBJECT
public:
SpectrumAnalyzerControlDialog( SpectrumAnalyzerControls* controls );
virtual ~SpectrumAnalyzerControlDialog()
{
}
Analyzer(Model *parent, const Descriptor::SubPluginFeatures::Key *key);
virtual ~Analyzer() {};
bool processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count) override;
EffectControls *controls() override {return &m_controls;}
SaProcessor *getProcessor() {return &m_processor;}
private:
virtual void paintEvent( QPaintEvent* event );
SaProcessor m_processor;
SaControls m_controls;
};
SpectrumAnalyzerControls* m_controls;
#endif // ANALYZER_H
QPixmap m_logXAxis;
QPixmap m_logYAxis;
} ;
#endif

View File

@@ -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)

View File

@@ -0,0 +1,19 @@
# Spectrum Analyzer plugin
## Overview
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.1 2019-06-02
- code style changes
- added tool-tips
- use const for unmodified arrays passed to fft_helpers
1.0.0 2019-04-07
- initial release

View File

@@ -0,0 +1,144 @@
/*
* SaControls.cpp - definition of SaControls class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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 "SaControls.h"
#include <QtXml/QDomElement>
#include "Analyzer.h"
#include "SaControlsDialog.h"
SaControls::SaControls(Analyzer *effect) :
EffectControls(effect),
m_effect(effect),
// initialize bool models and set default values
m_pauseModel(false, this, tr("Pause")),
m_refFreezeModel(false, this, tr("Reference freeze")),
m_waterfallModel(false, this, tr("Waterfall")),
m_smoothModel(false, this, tr("Averaging")),
m_stereoModel(false, this, tr("Stereo")),
m_peakHoldModel(false, this, tr("Peak hold")),
m_logXModel(true, this, tr("Logarithmic frequency")),
m_logYModel(true, this, tr("Logarithmic amplitude")),
// default values of combo boxes are set after they are populated
m_freqRangeModel(this, tr("Frequency range")),
m_ampRangeModel(this, tr("Amplitude range")),
m_blockSizeModel(this, tr("FFT block size")),
m_windowModel(this, tr("FFT window type"))
{
// Frequency and amplitude ranges; order must match
// FREQUENCY_RANGES and AMPLITUDE_RANGES defined in SaControls.h
m_freqRangeModel.addItem(tr("Full (auto)"));
m_freqRangeModel.addItem(tr("Audible"));
m_freqRangeModel.addItem(tr("Bass"));
m_freqRangeModel.addItem(tr("Mids"));
m_freqRangeModel.addItem(tr("High"));
m_freqRangeModel.setValue(m_freqRangeModel.findText(tr("Full (auto)")));
m_ampRangeModel.addItem(tr("Extended"));
m_ampRangeModel.addItem(tr("Default"));
m_ampRangeModel.addItem(tr("Audible"));
m_ampRangeModel.addItem(tr("Noise"));
m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Default")));
// FFT block size labels are generated automatically, based on
// FFT_BLOCK_SIZES vector defined in fft_helpers.h
for (unsigned int i = 0; i < FFT_BLOCK_SIZES.size(); i++)
{
if (i == 0)
{
m_blockSizeModel.addItem((std::to_string(FFT_BLOCK_SIZES[i]) + " ").c_str() + tr("(High time res.)"));
}
else if (i == FFT_BLOCK_SIZES.size() - 1)
{
m_blockSizeModel.addItem((std::to_string(FFT_BLOCK_SIZES[i]) + " ").c_str() + tr("(High freq. res.)"));
}
else
{
m_blockSizeModel.addItem(std::to_string(FFT_BLOCK_SIZES[i]).c_str());
}
}
m_blockSizeModel.setValue(m_blockSizeModel.findText("2048"));
// Window type order must match FFT_WINDOWS defined in fft_helpers.h
m_windowModel.addItem(tr("Rectangular (Off)"));
m_windowModel.addItem(tr("Blackman-Harris (Default)"));
m_windowModel.addItem(tr("Hamming"));
m_windowModel.addItem(tr("Hanning"));
m_windowModel.setValue(m_windowModel.findText(tr("Blackman-Harris (Default)")));
// Colors
// Background color is defined by Qt / theme.
// Make sure the sum of colors for L and R channel stays lower or equal
// to 255. Otherwise the Waterfall pixels may overflow back to 0 even when
// the input signal isn't clipping (over 1.0).
m_colorL = QColor(51, 148, 204, 135);
m_colorR = QColor(204, 107, 51, 135);
m_colorMono = QColor(51, 148, 204, 204);
m_colorBG = QColor(7, 7, 7, 255); // ~20 % gray (after gamma correction)
m_colorGrid = QColor(30, 34, 38, 255); // ~40 % gray (slightly cold / blue)
m_colorLabels = QColor(192, 202, 212, 255); // ~90 % gray (slightly cold / blue)
}
// Create the SaControlDialog widget which handles display of GUI elements.
EffectControlDialog* SaControls::createView()
{
return new SaControlsDialog(this, m_effect->getProcessor());
}
void SaControls::loadSettings(const QDomElement &_this)
{
m_waterfallModel.loadSettings(_this, "Waterfall");
m_smoothModel.loadSettings(_this, "Smooth");
m_stereoModel.loadSettings(_this, "Stereo");
m_peakHoldModel.loadSettings(_this, "PeakHold");
m_logXModel.loadSettings(_this, "LogX");
m_logYModel.loadSettings(_this, "LogY");
m_freqRangeModel.loadSettings(_this, "RangeX");
m_ampRangeModel.loadSettings(_this, "RangeY");
m_blockSizeModel.loadSettings(_this, "BlockSize");
m_windowModel.loadSettings(_this, "WindowType");
}
void SaControls::saveSettings(QDomDocument &doc, QDomElement &parent)
{
m_waterfallModel.saveSettings(doc, parent, "Waterfall");
m_smoothModel.saveSettings(doc, parent, "Smooth");
m_stereoModel.saveSettings(doc, parent, "Stereo");
m_peakHoldModel.saveSettings(doc, parent, "PeakHold");
m_logXModel.saveSettings(doc, parent, "LogX");
m_logYModel.saveSettings(doc, parent, "LogY");
m_freqRangeModel.saveSettings(doc, parent, "RangeX");
m_ampRangeModel.saveSettings(doc, parent, "RangeY");
m_blockSizeModel.saveSettings(doc, parent, "BlockSize");
m_windowModel.saveSettings(doc, parent, "WindowType");
}

View File

@@ -0,0 +1,126 @@
/*
* SaControls.h - declaration of SaControls class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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.
*
*/
#ifndef SACONTROLS_H
#define SACONTROLS_H
#include "ComboBoxModel.h"
#include "EffectControls.h"
//#define SA_DEBUG 1 // define SA_DEBUG to enable performance measurements
// Frequency ranges (in Hz).
// Full range is defined by LOWEST_LOG_FREQ and current sample rate.
const int LOWEST_LOG_FREQ = 10; // arbitrary low limit for log. scale, >1
enum FREQUENCY_RANGES
{
FRANGE_FULL = 0,
FRANGE_AUDIBLE,
FRANGE_BASS,
FRANGE_MIDS,
FRANGE_HIGH
};
const int FRANGE_AUDIBLE_START = 20;
const int FRANGE_AUDIBLE_END = 20000;
const int FRANGE_BASS_START = 20;
const int FRANGE_BASS_END = 300;
const int FRANGE_MIDS_START = 200;
const int FRANGE_MIDS_END = 5000;
const int FRANGE_HIGH_START = 4000;
const int FRANGE_HIGH_END = 20000;
// Amplitude ranges.
// Reference: sine wave from -1.0 to 1.0 = 0 dB.
// I.e. if master volume is 100 %, positive values signify clipping.
// Doubling or halving the amplitude produces 3 dB difference.
enum AMPLITUDE_RANGES
{
ARANGE_EXTENDED = 0,
ARANGE_DEFAULT,
ARANGE_AUDIBLE,
ARANGE_NOISE
};
const int ARANGE_EXTENDED_START = -80;
const int ARANGE_EXTENDED_END = 20;
const int ARANGE_DEFAULT_START = -30;
const int ARANGE_DEFAULT_END = 0;
const int ARANGE_AUDIBLE_START = -50;
const int ARANGE_AUDIBLE_END = 10;
const int ARANGE_NOISE_START = -60;
const int ARANGE_NOISE_END = -20;
class Analyzer;
// Holds all the configuration values
class SaControls : public EffectControls
{
Q_OBJECT
public:
explicit SaControls(Analyzer* effect);
virtual ~SaControls() {}
EffectControlDialog* createView() override;
void saveSettings (QDomDocument& doc, QDomElement& parent) override;
void loadSettings (const QDomElement &_this) override;
QString nodeName() const override {return "Analyzer";}
int controlCount() override {return 12;}
private:
Analyzer *m_effect;
BoolModel m_pauseModel;
BoolModel m_refFreezeModel;
BoolModel m_waterfallModel;
BoolModel m_smoothModel;
BoolModel m_stereoModel;
BoolModel m_peakHoldModel;
BoolModel m_logXModel;
BoolModel m_logYModel;
ComboBoxModel m_freqRangeModel;
ComboBoxModel m_ampRangeModel;
ComboBoxModel m_blockSizeModel;
ComboBoxModel m_windowModel;
QColor m_colorL;
QColor m_colorR;
QColor m_colorMono;
QColor m_colorBG;
QColor m_colorGrid;
QColor m_colorLabels;
friend class SaControlsDialog;
friend class SaSpectrumView;
friend class SaWaterfallView;
friend class SaProcessor;
};
#endif // SACONTROLS_H

View File

@@ -0,0 +1,227 @@
/*
* SaControlsDialog.cpp - definition of SaControlsDialog class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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 "SaControlsDialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QSizePolicy>
#include <QSplitter>
#include <QWidget>
#include "ComboBox.h"
#include "ComboBoxModel.h"
#include "embed.h"
#include "Engine.h"
#include "LedCheckbox.h"
#include "PixmapButton.h"
#include "SaControls.h"
#include "SaProcessor.h"
// The entire GUI layout is built here.
SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) :
EffectControlDialog(controls),
m_controls(controls),
m_processor(processor)
{
// Top level placement of sections is handled by QSplitter widget.
QHBoxLayout *master_layout = new QHBoxLayout;
QSplitter *display_splitter = new QSplitter(Qt::Vertical);
master_layout->addWidget(display_splitter);
master_layout->setContentsMargins(2, 6, 2, 8);
setLayout(master_layout);
// QSplitter top: configuration section
QWidget *config_widget = new QWidget;
QGridLayout *config_layout = new QGridLayout;
config_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
config_widget->setMaximumHeight(m_configHeight);
config_widget->setLayout(config_layout);
display_splitter->addWidget(config_widget);
// Pre-compute target pixmap size based on monitor DPI.
// Using setDevicePixelRatio() on pixmap allows the SVG image to be razor
// sharp on High-DPI screens, but the desired size must be manually
// enlarged. No idea how to make Qt do it in a more reasonable way.
QSize iconSize = QSize(22.0 * devicePixelRatio(), 22.0 * devicePixelRatio());
QSize buttonSize = 1.2 * iconSize;
// pause and freeze buttons
PixmapButton *pauseButton = new PixmapButton(this, tr("Pause"));
pauseButton->setToolTip(tr("Pause data acquisition"));
QPixmap *pauseOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("play").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *pauseOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("pause").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
pauseOnPixmap->setDevicePixelRatio(devicePixelRatio());
pauseOffPixmap->setDevicePixelRatio(devicePixelRatio());
pauseButton->setActiveGraphic(*pauseOnPixmap);
pauseButton->setInactiveGraphic(*pauseOffPixmap);
pauseButton->setCheckable(true);
pauseButton->setModel(&controls->m_pauseModel);
config_layout->addWidget(pauseButton, 0, 0, 2, 1);
PixmapButton *refFreezeButton = new PixmapButton(this, tr("Reference freeze"));
refFreezeButton->setToolTip(tr("Freeze current input as a reference / disable falloff in peak-hold mode."));
QPixmap *freezeOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *freezeOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze_off").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
freezeOnPixmap->setDevicePixelRatio(devicePixelRatio());
freezeOffPixmap->setDevicePixelRatio(devicePixelRatio());
refFreezeButton->setActiveGraphic(*freezeOnPixmap);
refFreezeButton->setInactiveGraphic(*freezeOffPixmap);
refFreezeButton->setCheckable(true);
refFreezeButton->setModel(&controls->m_refFreezeModel);
config_layout->addWidget(refFreezeButton, 2, 0, 2, 1);
// misc configuration switches
LedCheckBox *waterfallButton = new LedCheckBox(tr("Waterfall"), this);
waterfallButton->setToolTip(tr("Display real-time spectrogram"));
waterfallButton->setCheckable(true);
waterfallButton->setMinimumSize(70, 12);
waterfallButton->setModel(&controls->m_waterfallModel);
config_layout->addWidget(waterfallButton, 0, 1);
LedCheckBox *smoothButton = new LedCheckBox(tr("Averaging"), this);
smoothButton->setToolTip(tr("Enable exponential moving average"));
smoothButton->setCheckable(true);
smoothButton->setMinimumSize(70, 12);
smoothButton->setModel(&controls->m_smoothModel);
config_layout->addWidget(smoothButton, 1, 1);
LedCheckBox *stereoButton = new LedCheckBox(tr("Stereo"), this);
stereoButton->setToolTip(tr("Display stereo channels separately"));
stereoButton->setCheckable(true);
stereoButton->setMinimumSize(70, 12);
stereoButton->setModel(&controls->m_stereoModel);
config_layout->addWidget(stereoButton, 2, 1);
LedCheckBox *peakHoldButton = new LedCheckBox(tr("Peak hold"), this);
peakHoldButton->setToolTip(tr("Display envelope of peak values"));
peakHoldButton->setCheckable(true);
peakHoldButton->setMinimumSize(70, 12);
peakHoldButton->setModel(&controls->m_peakHoldModel);
config_layout->addWidget(peakHoldButton, 3, 1);
// frequency: linear / log. switch and range selector
PixmapButton *logXButton = new PixmapButton(this, tr("Logarithmic frequency"));
logXButton->setToolTip(tr("Switch between logarithmic and linear frequency scale"));
QPixmap *logXOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *logXOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
logXOnPixmap->setDevicePixelRatio(devicePixelRatio());
logXOffPixmap->setDevicePixelRatio(devicePixelRatio());
logXButton->setActiveGraphic(*logXOnPixmap);
logXButton->setInactiveGraphic(*logXOffPixmap);
logXButton->setCheckable(true);
logXButton->setModel(&controls->m_logXModel);
config_layout->addWidget(logXButton, 0, 2, 2, 1, Qt::AlignRight);
ComboBox *freqRangeCombo = new ComboBox(this, tr("Frequency range"));
freqRangeCombo->setToolTip(tr("Frequency range"));
freqRangeCombo->setMinimumSize(100, 22);
freqRangeCombo->setMaximumSize(200, 22);
freqRangeCombo->setModel(&controls->m_freqRangeModel);
config_layout->addWidget(freqRangeCombo, 0, 3, 2, 1);
// amplitude: linear / log switch and range selector
PixmapButton *logYButton = new PixmapButton(this, tr("Logarithmic amplitude"));
logYButton->setToolTip(tr("Switch between logarithmic and linear amplitude scale"));
QPixmap *logYOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *logYOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
logYOnPixmap->setDevicePixelRatio(devicePixelRatio());
logYOffPixmap->setDevicePixelRatio(devicePixelRatio());
logYButton->setActiveGraphic(*logYOnPixmap);
logYButton->setInactiveGraphic(*logYOffPixmap);
logYButton->setCheckable(true);
logYButton->setModel(&controls->m_logYModel);
config_layout->addWidget(logYButton, 2, 2, 2, 1, Qt::AlignRight);
ComboBox *ampRangeCombo = new ComboBox(this, tr("Amplitude range"));
ampRangeCombo->setToolTip(tr("Amplitude range"));
ampRangeCombo->setMinimumSize(100, 22);
ampRangeCombo->setMaximumSize(200, 22);
ampRangeCombo->setModel(&controls->m_ampRangeModel);
config_layout->addWidget(ampRangeCombo, 2, 3, 2, 1);
// FFT: block size: icon and selector
QLabel *blockSizeLabel = new QLabel("", this);
QPixmap *blockSizeIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("block_size"));
blockSizeIcon->setDevicePixelRatio(devicePixelRatio());
blockSizeLabel->setPixmap(blockSizeIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
config_layout->addWidget(blockSizeLabel, 0, 4, 2, 1, Qt::AlignRight);
ComboBox *blockSizeCombo = new ComboBox(this, tr("FFT block bize"));
blockSizeCombo->setToolTip(tr("FFT block size"));
blockSizeCombo->setMinimumSize(100, 22);
blockSizeCombo->setMaximumSize(200, 22);
blockSizeCombo->setModel(&controls->m_blockSizeModel);
config_layout->addWidget(blockSizeCombo, 0, 5, 2, 1);
processor->reallocateBuffers();
connect(&controls->m_blockSizeModel, &ComboBoxModel::dataChanged, [=] {processor->reallocateBuffers();});
// FFT: window type: icon and selector
QLabel *windowLabel = new QLabel("", this);
QPixmap *windowIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("window"));
windowIcon->setDevicePixelRatio(devicePixelRatio());
windowLabel->setPixmap(windowIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
config_layout->addWidget(windowLabel, 2, 4, 2, 1, Qt::AlignRight);
ComboBox *windowCombo = new ComboBox(this, tr("FFT window type"));
windowCombo->setToolTip(tr("FFT window type"));
windowCombo->setMinimumSize(100, 22);
windowCombo->setMaximumSize(200, 22);
windowCombo->setModel(&controls->m_windowModel);
config_layout->addWidget(windowCombo, 2, 5, 2, 1);
processor->rebuildWindow();
connect(&controls->m_windowModel, &ComboBoxModel::dataChanged, [=] {processor->rebuildWindow();});
// QSplitter middle and bottom: spectrum display widgets
m_spectrum = new SaSpectrumView(controls, processor, this);
display_splitter->addWidget(m_spectrum);
m_waterfall = new SaWaterfallView(controls, processor, this);
display_splitter->addWidget(m_waterfall);
m_waterfall->setVisible(m_controls->m_waterfallModel.value());
connect(&controls->m_waterfallModel, &BoolModel::dataChanged, [=] {m_waterfall->updateVisibility();});
}
// Suggest the best current widget size.
QSize SaControlsDialog::sizeHint() const
{
// Best width is determined by spectrum display sizeHint.
// Best height depends on whether waterfall is visible and
// consists of heights of the config section, spectrum, waterfall
// and some reserve for margins.
if (m_waterfall->isVisible())
{
return QSize(m_spectrum->sizeHint().width(),
m_configHeight + m_spectrum->sizeHint().height() + m_waterfall->sizeHint().height() + 50);
}
else
{
return QSize(m_spectrum->sizeHint().width(),
m_configHeight + m_spectrum->sizeHint().height() + 50);
}
}

View File

@@ -0,0 +1,57 @@
/*
* SaControlsDialog.h - declatation of SaControlsDialog class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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.
*
*/
#ifndef SACONTROLSDIALOG_H
#define SACONTROLSDIALOG_H
#include "EffectControlDialog.h"
#include "SaControls.h"
#include "SaSpectrumView.h"
#include "SaProcessor.h"
#include "SaWaterfallView.h"
//! Top-level widget holding the configuration GUI and spectrum displays
class SaControlsDialog : public EffectControlDialog
{
Q_OBJECT
public:
explicit SaControlsDialog(SaControls *controls, SaProcessor *processor);
virtual ~SaControlsDialog() {}
bool isResizable() const override {return true;}
QSize sizeHint() const override;
private:
SaControls *m_controls;
SaProcessor *m_processor;
// Pointers to created widgets are needed to keep track of their sizeHint() changes.
// Config widget is a plain QWidget so it has just a fixed height instead.
const int m_configHeight = 75;
SaSpectrumView *m_spectrum;
SaWaterfallView *m_waterfall;
};
#endif // SACONTROLSDIALOG_H

View File

@@ -0,0 +1,571 @@
/* SaProcessor.cpp - implementation of SaProcessor 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 "SaProcessor.h"
#include <algorithm>
#include <cmath>
#include <iostream>
#include <QMutexLocker>
#include "lmms_math.h"
SaProcessor::SaProcessor(SaControls *controls) :
m_controls(controls),
m_inBlockSize(FFT_BLOCK_SIZES[0]),
m_fftBlockSize(FFT_BLOCK_SIZES[0]),
m_sampleRate(Engine::mixer()->processingSampleRate()),
m_framesFilledUp(0),
m_spectrumActive(false),
m_waterfallActive(false),
m_waterfallNotEmpty(0),
m_reallocating(false)
{
m_fftWindow.resize(m_inBlockSize, 1.0);
precomputeWindow(m_fftWindow.data(), m_inBlockSize, BLACKMAN_HARRIS);
m_bufferL.resize(m_fftBlockSize, 0);
m_bufferR.resize(m_fftBlockSize, 0);
m_spectrumL = (fftwf_complex *) fftwf_malloc(binCount() * sizeof (fftwf_complex));
m_spectrumR = (fftwf_complex *) fftwf_malloc(binCount() * sizeof (fftwf_complex));
m_fftPlanL = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_bufferL.data(), m_spectrumL, FFTW_MEASURE);
m_fftPlanR = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_bufferR.data(), m_spectrumR, FFTW_MEASURE);
m_absSpectrumL.resize(binCount(), 0);
m_absSpectrumR.resize(binCount(), 0);
m_normSpectrumL.resize(binCount(), 0);
m_normSpectrumR.resize(binCount(), 0);
m_history.resize(binCount() * m_waterfallHeight * sizeof qRgb(0,0,0), 0);
clear();
}
SaProcessor::~SaProcessor()
{
if (m_fftPlanL != NULL) {fftwf_destroy_plan(m_fftPlanL);}
if (m_fftPlanR != NULL) {fftwf_destroy_plan(m_fftPlanR);}
if (m_spectrumL != NULL) {fftwf_free(m_spectrumL);}
if (m_spectrumR != NULL) {fftwf_free(m_spectrumR);}
m_fftPlanL = NULL;
m_fftPlanR = NULL;
m_spectrumL = NULL;
m_spectrumR = NULL;
}
// Load a batch of data from LMMS; run FFT analysis if buffer is full enough.
void SaProcessor::analyse(sampleFrame *in_buffer, const fpp_t frame_count)
{
#ifdef SA_DEBUG
int start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// only take in data if any view is visible and not paused
if ((m_spectrumActive || m_waterfallActive) && !m_controls->m_pauseModel.value())
{
const bool stereo = m_controls->m_stereoModel.value();
fpp_t in_frame = 0;
while (in_frame < frame_count)
{
// fill sample buffers and check for zero input
bool block_empty = true;
for (; in_frame < frame_count && m_framesFilledUp < m_inBlockSize; in_frame++, m_framesFilledUp++)
{
if (stereo)
{
m_bufferL[m_framesFilledUp] = in_buffer[in_frame][0];
m_bufferR[m_framesFilledUp] = in_buffer[in_frame][1];
}
else
{
m_bufferL[m_framesFilledUp] =
m_bufferR[m_framesFilledUp] = (in_buffer[in_frame][0] + in_buffer[in_frame][1]) * 0.5f;
}
if (in_buffer[in_frame][0] != 0.f || in_buffer[in_frame][1] != 0.f)
{
block_empty = false;
}
}
// Run analysis only if buffers contain enough data.
// Also, to prevent audio interruption and a momentary GUI freeze,
// skip analysis if buffers are being reallocated.
if (m_framesFilledUp < m_inBlockSize || m_reallocating) {return;}
// update sample rate
m_sampleRate = Engine::mixer()->processingSampleRate();
// apply FFT window
for (unsigned int i = 0; i < m_inBlockSize; i++)
{
m_bufferL[i] = m_bufferL[i] * m_fftWindow[i];
m_bufferR[i] = m_bufferR[i] * m_fftWindow[i];
}
// lock data shared with SaSpectrumView and SaWaterfallView
QMutexLocker lock(&m_dataAccess);
// Run FFT on left channel, convert the result to absolute magnitude
// spectrum and normalize it.
fftwf_execute(m_fftPlanL);
absspec(m_spectrumL, m_absSpectrumL.data(), binCount());
normalize(m_absSpectrumL, m_normSpectrumL, m_inBlockSize);
// repeat analysis for right channel if stereo processing is enabled
if (stereo)
{
fftwf_execute(m_fftPlanR);
absspec(m_spectrumR, m_absSpectrumR.data(), binCount());
normalize(m_absSpectrumR, m_normSpectrumR, m_inBlockSize);
}
// count empty lines so that empty history does not have to update
if (block_empty && m_waterfallNotEmpty)
{
m_waterfallNotEmpty -= 1;
}
else if (!block_empty)
{
m_waterfallNotEmpty = m_waterfallHeight + 2;
}
if (m_waterfallActive && m_waterfallNotEmpty)
{
// move waterfall history one line down and clear the top line
QRgb *pixel = (QRgb *)m_history.data();
std::copy(pixel,
pixel + binCount() * m_waterfallHeight - binCount(),
pixel + binCount());
memset(pixel, 0, binCount() * sizeof (QRgb));
// add newest result on top
int target; // pixel being constructed
float accL = 0; // accumulators for merging multiple bins
float accR = 0;
for (unsigned int i = 0; i < binCount(); i++)
{
// Every frequency bin spans a frequency range that must be
// partially or fully mapped to a pixel. Any inconsistency
// may be seen in the spectrogram as dark or white lines --
// play white noise to confirm your change did not break it.
float band_start = freqToXPixel(binToFreq(i) - binBandwidth() / 2.0, binCount());
float band_end = freqToXPixel(binToFreq(i + 1) - binBandwidth() / 2.0, binCount());
if (m_controls->m_logXModel.value())
{
// Logarithmic scale
if (band_end - band_start > 1.0)
{
// band spans multiple pixels: draw all pixels it covers
for (target = (int)band_start; target < (int)band_end; target++)
{
if (target >= 0 && target < binCount())
{
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
}
}
// save remaining portion of the band for the following band / pixel
// (in case the next band uses sub-pixel drawing)
accL = (band_end - (int)band_end) * m_normSpectrumL[i];
accR = (band_end - (int)band_end) * m_normSpectrumR[i];
}
else
{
// sub-pixel drawing; add contribution of current band
target = (int)band_start;
if ((int)band_start == (int)band_end)
{
// band ends within current target pixel, accumulate
accL += (band_end - band_start) * m_normSpectrumL[i];
accR += (band_end - band_start) * m_normSpectrumR[i];
}
else
{
// Band ends in the next pixel -- finalize the current pixel.
// Make sure contribution is split correctly on pixel boundary.
accL += ((int)band_end - band_start) * m_normSpectrumL[i];
accR += ((int)band_end - band_start) * m_normSpectrumR[i];
if (target >= 0 && target < binCount()) {pixel[target] = makePixel(accL, accR);}
// save remaining portion of the band for the following band / pixel
accL = (band_end - (int)band_end) * m_normSpectrumL[i];
accR = (band_end - (int)band_end) * m_normSpectrumR[i];
}
}
}
else
{
// Linear: always draws one or more pixels per band
for (target = (int)band_start; target < band_end; target++)
{
if (target >= 0 && target < binCount())
{
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
}
}
}
}
}
#ifdef SA_DEBUG
// report FFT processing speed
start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - start_time;
std::cout << "Processed " << m_framesFilledUp << " samples in " << start_time / 1000000.0 << " ms" << std::endl;
#endif
// clean up before checking for more data from input buffer
m_framesFilledUp = 0;
}
}
}
// Produce a spectrogram pixel from normalized spectrum data.
// Values over 1.0 will cause the color components to overflow: this is left
// intentionally untreated as it clearly indicates which frequency is clipping.
// Gamma correction is applied to make small values more visible and to make
// a linear gradient actually appear roughly linear. The correction should be
// around 0.42 to 0.45 for sRGB displays (or lower for bigger visibility boost).
QRgb SaProcessor::makePixel(float left, float right, float gamma_correction) const
{
if (m_controls->m_stereoModel.value())
{
float ampL = pow(left, gamma_correction);
float ampR = pow(right, gamma_correction);
return qRgb(m_controls->m_colorL.red() * ampL + m_controls->m_colorR.red() * ampR,
m_controls->m_colorL.green() * ampL + m_controls->m_colorR.green() * ampR,
m_controls->m_colorL.blue() * ampL + m_controls->m_colorR.blue() * ampR);
}
else
{
float ampL = pow(left, gamma_correction);
// make mono color brighter to compensate for the fact it is not summed
return qRgb(m_controls->m_colorMono.lighter().red() * ampL,
m_controls->m_colorMono.lighter().green() * ampL,
m_controls->m_colorMono.lighter().blue() * ampL);
}
}
// Inform the processor whether any display widgets actually need it.
void SaProcessor::setSpectrumActive(bool active)
{
m_spectrumActive = active;
}
void SaProcessor::setWaterfallActive(bool active)
{
m_waterfallActive = active;
}
// Reallocate data buffers according to newly set block size.
void SaProcessor::reallocateBuffers()
{
unsigned int new_size_index = m_controls->m_blockSizeModel.value();
unsigned int new_in_size, new_fft_size;
unsigned int new_bins;
// get new block sizes and bin count based on selected index
if (new_size_index < FFT_BLOCK_SIZES.size())
{
new_in_size = FFT_BLOCK_SIZES[new_size_index];
}
else
{
new_in_size = FFT_BLOCK_SIZES.back();
}
if (new_size_index + m_zeroPadFactor < FFT_BLOCK_SIZES.size())
{
new_fft_size = FFT_BLOCK_SIZES[new_size_index + m_zeroPadFactor];
}
else
{
new_fft_size = FFT_BLOCK_SIZES.back();
}
new_bins = new_fft_size / 2 +1;
// Lock data shared with SaSpectrumView and SaWaterfallView.
// The m_reallocating is here to tell analyse() to avoid asking for the
// lock, since fftw3 can take a while to find the fastest FFT algorithm
// for given machine, which would produce interruption in the audio stream.
m_reallocating = true;
QMutexLocker lock(&m_dataAccess);
// destroy old FFT plan and free the result buffer
if (m_fftPlanL != NULL) {fftwf_destroy_plan(m_fftPlanL);}
if (m_fftPlanR != NULL) {fftwf_destroy_plan(m_fftPlanR);}
if (m_spectrumL != NULL) {fftwf_free(m_spectrumL);}
if (m_spectrumR != NULL) {fftwf_free(m_spectrumR);}
// allocate new space, create new plan and resize containers
m_fftWindow.resize(new_in_size, 1.0);
precomputeWindow(m_fftWindow.data(), new_in_size, (FFT_WINDOWS) m_controls->m_windowModel.value());
m_bufferL.resize(new_fft_size, 0);
m_bufferR.resize(new_fft_size, 0);
m_spectrumL = (fftwf_complex *) fftwf_malloc(new_bins * sizeof (fftwf_complex));
m_spectrumR = (fftwf_complex *) fftwf_malloc(new_bins * sizeof (fftwf_complex));
m_fftPlanL = fftwf_plan_dft_r2c_1d(new_fft_size, m_bufferL.data(), m_spectrumL, FFTW_MEASURE);
m_fftPlanR = fftwf_plan_dft_r2c_1d(new_fft_size, m_bufferR.data(), m_spectrumR, FFTW_MEASURE);
if (m_fftPlanL == NULL || m_fftPlanR == NULL)
{
std::cerr << "Failed to create new FFT plan!" << std::endl;
}
m_absSpectrumL.resize(new_bins, 0);
m_absSpectrumR.resize(new_bins, 0);
m_normSpectrumL.resize(new_bins, 0);
m_normSpectrumR.resize(new_bins, 0);
m_history.resize(new_bins * m_waterfallHeight * sizeof qRgb(0,0,0), 0);
// done; publish new sizes and clean up
m_inBlockSize = new_in_size;
m_fftBlockSize = new_fft_size;
lock.unlock();
m_reallocating = false;
clear();
}
// Precompute a new FFT window based on currently selected type.
void SaProcessor::rebuildWindow()
{
// computation is done in fft_helpers
QMutexLocker lock(&m_dataAccess);
precomputeWindow(m_fftWindow.data(), m_inBlockSize, (FFT_WINDOWS) m_controls->m_windowModel.value());
}
// Clear all data buffers and replace contents with zeros.
// Note: may take a few milliseconds, do not call in a loop!
void SaProcessor::clear()
{
QMutexLocker lock(&m_dataAccess);
m_framesFilledUp = 0;
std::fill(m_bufferL.begin(), m_bufferL.end(), 0);
std::fill(m_bufferR.begin(), m_bufferR.end(), 0);
std::fill(m_absSpectrumL.begin(), m_absSpectrumL.end(), 0);
std::fill(m_absSpectrumR.begin(), m_absSpectrumR.end(), 0);
std::fill(m_normSpectrumL.begin(), m_normSpectrumL.end(), 0);
std::fill(m_normSpectrumR.begin(), m_normSpectrumR.end(), 0);
std::fill(m_history.begin(), m_history.end(), 0);
}
// --------------------------------------
// Frequency conversion helpers
//
// Get sample rate value that is valid for currently stored results.
unsigned int SaProcessor::getSampleRate() const
{
return m_sampleRate;
}
// Maximum frequency of a sampled signal is equal to half of its sample rate.
float SaProcessor::getNyquistFreq() const
{
return getSampleRate() / 2.0f;
}
// FFTW automatically discards upper half of the symmetric FFT output, so
// the useful bin count is the transform size divided by 2, plus zero.
unsigned int SaProcessor::binCount() const
{
return m_fftBlockSize / 2 + 1;
}
// Return the center frequency of given frequency bin.
float SaProcessor::binToFreq(unsigned int bin_index) const
{
return getNyquistFreq() * bin_index / binCount();
}
// Return width of the frequency range that falls into one bin.
// The binCount is lowered by one since half of the first and last bin is
// actually outside the frequency range.
float SaProcessor::binBandwidth() const
{
return getNyquistFreq() / (binCount() - 1);
}
float SaProcessor::getFreqRangeMin(bool linear) const
{
switch (m_controls->m_freqRangeModel.value())
{
case FRANGE_AUDIBLE: return FRANGE_AUDIBLE_START;
case FRANGE_BASS: return FRANGE_BASS_START;
case FRANGE_MIDS: return FRANGE_MIDS_START;
case FRANGE_HIGH: return FRANGE_HIGH_START;
default:
case FRANGE_FULL: return linear ? 0 : LOWEST_LOG_FREQ;
}
}
float SaProcessor::getFreqRangeMax() const
{
switch (m_controls->m_freqRangeModel.value())
{
case FRANGE_AUDIBLE: return FRANGE_AUDIBLE_END;
case FRANGE_BASS: return FRANGE_BASS_END;
case FRANGE_MIDS: return FRANGE_MIDS_END;
case FRANGE_HIGH: return FRANGE_HIGH_END;
default:
case FRANGE_FULL: return getNyquistFreq();
}
}
// Map frequency to pixel x position on a display of given width.
float SaProcessor::freqToXPixel(float freq, unsigned int width) const
{
if (m_controls->m_logXModel.value())
{
if (freq <= 1) {return 0;}
float min = log10(getFreqRangeMin());
float range = log10(getFreqRangeMax()) - min;
return (log10(freq) - min) / range * width;
}
else
{
float min = getFreqRangeMin();
float range = getFreqRangeMax() - min;
return (freq - min) / range * width;
}
}
// Map pixel x position on display of given width back to frequency.
float SaProcessor::xPixelToFreq(float x, unsigned int width) const
{
if (m_controls->m_logXModel.value())
{
float min = log10(getFreqRangeMin());
float max = log10(getFreqRangeMax());
float range = max - min;
return pow(10, min + x / width * range);
}
else
{
float min = getFreqRangeMin();
float range = getFreqRangeMax() - min;
return min + x / width * range;
}
}
// --------------------------------------
// Amplitude conversion helpers
//
float SaProcessor::getAmpRangeMin(bool linear) const
{
// return very low limit to make sure zero gets included at linear grid
if (linear) {return -900;}
switch (m_controls->m_ampRangeModel.value())
{
case ARANGE_EXTENDED: return ARANGE_EXTENDED_START;
case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_START;
case ARANGE_NOISE: return ARANGE_NOISE_START;
default:
case ARANGE_DEFAULT: return ARANGE_DEFAULT_START;
}
}
float SaProcessor::getAmpRangeMax() const
{
switch (m_controls->m_ampRangeModel.value())
{
case ARANGE_EXTENDED: return ARANGE_EXTENDED_END;
case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_END;
case ARANGE_NOISE: return ARANGE_NOISE_END;
default:
case ARANGE_DEFAULT: return ARANGE_DEFAULT_END;
}
}
// Map linear amplitude to pixel y position on a display of given height.
// Note that display coordinates are flipped: amplitude grows from [height] to zero.
float SaProcessor::ampToYPixel(float amplitude, unsigned int height) const
{
if (m_controls->m_logYModel.value())
{
// logarithmic scale: convert linear amplitude to dB (relative to 1.0)
float amplitude_dB = 10 * log10(amplitude);
if (amplitude_dB < getAmpRangeMin())
{
return height;
}
else
{
float max = getAmpRangeMax();
float range = getAmpRangeMin() - max;
return (amplitude_dB - max) / range * height;
}
}
else
{
// linear scale: convert returned ranges from dB to linear scale
float max = pow(10, getAmpRangeMax() / 10);
float range = pow(10, getAmpRangeMin() / 10) - max;
return (amplitude - max) / range * height;
}
}
// Map pixel y position on display of given height back to amplitude.
// Note that display coordinates are flipped: amplitude grows from [height] to zero.
// Also note that in logarithmic Y mode the returned amplitude is in dB, not linear.
float SaProcessor::yPixelToAmp(float y, unsigned int height) const
{
if (m_controls->m_logYModel.value())
{
float max = getAmpRangeMax();
float range = getAmpRangeMin() - max;
return max + range * (y / height);
}
else
{
// linear scale: convert returned ranges from dB to linear scale
float max = pow(10, getAmpRangeMax() / 10);
float range = pow(10, getAmpRangeMin() / 10) - max;
return max + range * (y / height);
}
}

View File

@@ -0,0 +1,122 @@
/* SaProcessor.h - declaration of SaProcessor class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014 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.
*
*/
#ifndef SAPROCESSOR_H
#define SAPROCESSOR_H
#include <QColor>
#include <QMutex>
#include <vector>
#include "fft_helpers.h"
#include "SaControls.h"
//! Receives audio data, runs FFT analysis and stores the result.
class SaProcessor
{
public:
explicit SaProcessor(SaControls *controls);
virtual ~SaProcessor();
void analyse(sampleFrame *in_buffer, const fpp_t frame_count);
// inform processor if any processing is actually required
void setSpectrumActive(bool active);
void setWaterfallActive(bool active);
// configuration is taken from models in SaControls; some changes require
// an exlicit update request (reallocation and window rebuild)
void reallocateBuffers();
void rebuildWindow();
void clear();
// information about results and unit conversion helpers
float binToFreq(unsigned int bin_index) const;
float binBandwidth() const;
float freqToXPixel(float frequency, unsigned int width) const;
float xPixelToFreq(float x, unsigned int width) const;
float ampToYPixel(float amplitude, unsigned int height) const;
float yPixelToAmp(float y, unsigned int height) const;
unsigned int getSampleRate() const;
float getNyquistFreq() const;
float getFreqRangeMin(bool linear = false) const;
float getFreqRangeMax() const;
float getAmpRangeMin(bool linear = false) const;
float getAmpRangeMax() const;
// data access lock must be acquired by any friendly class that touches
// the results, mainly to prevent unexpected mid-way reallocation
QMutex m_dataAccess;
private:
SaControls *m_controls;
// currently valid configuration
const unsigned int m_zeroPadFactor = 2; //!< use n-steps bigger FFT for given block size
unsigned int m_inBlockSize; //!< size of input (time domain) data block
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)
std::vector<float> m_bufferR; //!< time domain samples (right)
std::vector<float> m_fftWindow; //!< precomputed window function coefficients
fftwf_plan m_fftPlanL;
fftwf_plan m_fftPlanR;
fftwf_complex *m_spectrumL; //!< frequency domain samples (complex) (left)
fftwf_complex *m_spectrumR; //!< frequency domain samples (complex) (right)
std::vector<float> m_absSpectrumL; //!< frequency domain samples (absolute) (left)
std::vector<float> m_absSpectrumR; //!< frequency domain samples (absolute) (right)
std::vector<float> m_normSpectrumL; //!< frequency domain samples (normalized) (left)
std::vector<float> m_normSpectrumR; //!< frequency domain samples (normalized) (right)
// spectrum history for waterfall: new normSpectrum lines are added on top
std::vector<uchar> m_history;
const unsigned int m_waterfallHeight = 200; // Number of stored lines.
// Note: high values may make it harder to see transients.
// book keeping
bool m_spectrumActive;
bool m_waterfallActive;
unsigned int m_waterfallNotEmpty;
bool m_reallocating;
// merge L and R channels and apply gamma correction to make a spectrogram pixel
QRgb makePixel(float left, float right, float gamma_correction = 0.30) const;
friend class SaSpectrumView;
friend class SaWaterfallView;
};
#endif // SAPROCESSOR_H

View File

@@ -0,0 +1,796 @@
/* SaSpectrumView.cpp - implementation of SaSpectrumView 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 "SaSpectrumView.h"
#include <algorithm>
#include <cmath>
#include <QMouseEvent>
#include <QMutexLocker>
#include <QPainter>
#include <QString>
#include "GuiApplication.h"
#include "MainWindow.h"
#include "SaProcessor.h"
#ifdef SA_DEBUG
#include <chrono>
#include <iostream>
#endif
SaSpectrumView::SaSpectrumView(SaControls *controls, SaProcessor *processor, QWidget *_parent) :
QWidget(_parent),
m_controls(controls),
m_processor(processor),
m_freezeRequest(false),
m_frozen(false)
{
setMinimumSize(360, 170);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(gui->mainWindow(), SIGNAL(periodicUpdate()), this, SLOT(periodicUpdate()));
m_displayBufferL.resize(m_processor->binCount(), 0);
m_displayBufferR.resize(m_processor->binCount(), 0);
m_peakBufferL.resize(m_processor->binCount(), 0);
m_peakBufferR.resize(m_processor->binCount(), 0);
m_freqRangeIndex = m_controls->m_freqRangeModel.value();
m_ampRangeIndex = m_controls->m_ampRangeModel.value();
m_logFreqTics = makeLogFreqTics(m_processor->getFreqRangeMin(), m_processor->getFreqRangeMax());
m_linearFreqTics = makeLinearFreqTics(m_processor->getFreqRangeMin(), m_processor->getFreqRangeMax());
m_logAmpTics = makeLogAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax());
m_linearAmpTics = makeLinearAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax());
m_cursor = QPoint(0, 0);
}
// Compose and draw all the content; periodically called by Qt.
// NOTE: Performance sensitive! If the drawing takes too long, it will drag
// the FPS down for the entire program! Use SA_DEBUG to display timings.
void SaSpectrumView::paintEvent(QPaintEvent *event)
{
#ifdef SA_DEBUG
int total_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// 0) Constants and init
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
// drawing and path-making are split into multiple methods for clarity;
// display boundaries are updated here and shared as member variables
m_displayTop = 1;
m_displayBottom = height() -20;
m_displayLeft = 26;
m_displayRight = width() -26;
m_displayWidth = m_displayRight - m_displayLeft;
// recompute range labels if needed
if (m_freqRangeIndex != m_controls->m_freqRangeModel.value())
{
m_logFreqTics = makeLogFreqTics(m_processor->getFreqRangeMin(), m_processor->getFreqRangeMax());
m_linearFreqTics = makeLinearFreqTics(m_processor->getFreqRangeMin(true), m_processor->getFreqRangeMax());
m_freqRangeIndex = m_controls->m_freqRangeModel.value();
}
if (m_ampRangeIndex != m_controls->m_ampRangeModel.value())
{
m_logAmpTics = makeLogAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax());
m_linearAmpTics = makeLinearAmpTics(m_processor->getAmpRangeMin(true), m_processor->getAmpRangeMax());
m_ampRangeIndex = m_controls->m_ampRangeModel.value();
}
// generate freeze request or clear "frozen" status based on freeze button
if (!m_frozen && m_controls->m_refFreezeModel.value())
{
m_freezeRequest = true;
}
else if (!m_controls->m_refFreezeModel.value())
{
m_frozen = false;
}
// 1) Background, grid and labels
drawGrid(painter);
// 2) Spectrum display
drawSpectrum(painter);
// 3) Overlays
// draw cursor (if it is within bounds)
drawCursor(painter);
// always draw the display outline
painter.setPen(QPen(m_controls->m_colorGrid, 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawRoundedRect(m_displayLeft, 1,
m_displayWidth, m_displayBottom,
2.0, 2.0);
#ifdef SA_DEBUG
// display what FPS would be achieved if spectrum display ran in a loop
total_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - total_time;
painter.setPen(QPen(m_controls->m_colorLabels, 1,
Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawText(m_displayRight -100, 70, 100, 16, Qt::AlignLeft,
QString(std::string("Max FPS: " + std::to_string(1000000000.0 / total_time)).c_str()));
#endif
}
// Refresh data and draw the spectrum.
void SaSpectrumView::drawSpectrum(QPainter &painter)
{
#ifdef SA_DEBUG
int path_time = 0, draw_time = 0;
#endif
// draw the graph only if there is any input, averaging residue or peaks
QMutexLocker lock(&m_processor->m_dataAccess);
if (m_decaySum > 0 || notEmpty(m_processor->m_normSpectrumL) || notEmpty(m_processor->m_normSpectrumR))
{
lock.unlock();
#ifdef SA_DEBUG
path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// update data buffers and reconstruct paths
refreshPaths();
#ifdef SA_DEBUG
path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - path_time;
#endif
// draw stored paths
#ifdef SA_DEBUG
draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// in case stereo is disabled, mono data are stored in left channel structures
if (m_controls->m_stereoModel.value())
{
painter.fillPath(m_pathR, QBrush(m_controls->m_colorR));
painter.fillPath(m_pathL, QBrush(m_controls->m_colorL));
}
else
{
painter.fillPath(m_pathL, QBrush(m_controls->m_colorMono));
}
// draw the peakBuffer only if peak hold or reference freeze is active
if (m_controls->m_peakHoldModel.value() || m_controls->m_refFreezeModel.value())
{
if (m_controls->m_stereoModel.value())
{
painter.setPen(QPen(m_controls->m_colorR, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawPath(m_pathPeakR);
painter.setPen(QPen(m_controls->m_colorL, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawPath(m_pathPeakL);
}
else
{
painter.setPen(QPen(m_controls->m_colorL, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawPath(m_pathPeakL);
}
}
#ifdef SA_DEBUG
draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - draw_time;
#endif
}
else
{
lock.unlock();
}
#ifdef SA_DEBUG
// display measurement results
painter.drawText(m_displayRight -100, 90, 100, 16, Qt::AlignLeft,
QString(std::string("Path ms: " + std::to_string(path_time / 1000000.0)).c_str()));
painter.drawText(m_displayRight -100, 110, 100, 16, Qt::AlignLeft,
QString(std::string("Draw ms: " + std::to_string(draw_time / 1000000.0)).c_str()));
#endif
}
// Read newest FFT results from SaProcessor, update local display buffers
// and build QPainter paths.
void SaSpectrumView::refreshPaths()
{
// Lock is required for the entire function, mainly to prevent block size
// changes from causing reallocation of data structures mid-way.
QMutexLocker lock(&m_processor->m_dataAccess);
// check if bin count changed and reallocate display buffers accordingly
if (m_processor->binCount() != m_displayBufferL.size())
{
m_displayBufferL.clear();
m_displayBufferR.clear();
m_peakBufferL.clear();
m_peakBufferR.clear();
m_displayBufferL.resize(m_processor->binCount(), 0);
m_displayBufferR.resize(m_processor->binCount(), 0);
m_peakBufferL.resize(m_processor->binCount(), 0);
m_peakBufferR.resize(m_processor->binCount(), 0);
}
// update display buffers for left and right channel
#ifdef SA_DEBUG
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());
#ifdef SA_DEBUG
refresh_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - refresh_time;
#endif
// if there was a freeze request, it was taken care of during the update
if (m_controls->m_refFreezeModel.value() && m_freezeRequest)
{
m_freezeRequest = false;
m_frozen = true;
}
#ifdef SA_DEBUG
int make_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// Use updated display buffers to prepare new paths for QPainter.
// This is the second slowest action (first is the subsequent drawing); use
// the resolution parameter to balance display quality and performance.
m_pathL = makePath(m_displayBufferL, 1.5);
if (m_controls->m_stereoModel.value())
{
m_pathR = makePath(m_displayBufferR, 1.5);
}
if (m_controls->m_peakHoldModel.value() || m_controls->m_refFreezeModel.value())
{
m_pathPeakL = makePath(m_peakBufferL, 0.25);
if (m_controls->m_stereoModel.value())
{
m_pathPeakR = makePath(m_peakBufferR, 0.25);
}
}
#ifdef SA_DEBUG
make_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - make_time;
#endif
#ifdef SA_DEBUG
// print measurement results
std::cout << "Buffer update ms: " << std::to_string(refresh_time / 1000000.0) << ", ";
std::cout << "Path-make ms: " << std::to_string(make_time / 1000000.0) << std::endl;
#endif
}
// Update display buffers: add new data, update average and peaks / reference.
// Output the sum of all displayed values -- draw only if it is non-zero.
// NOTE: The calling function is responsible for acquiring SaProcessor data
// access lock!
void SaSpectrumView::updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer)
{
for (int n = 0; n < m_processor->binCount(); n++)
{
// Update the exponential average if enabled, or simply copy the value.
if (!m_controls->m_pauseModel.value())
{
if (m_controls->m_smoothModel.value())
{
displayBuffer[n] = spectrum[n] * m_smoothFactor + displayBuffer[n] * (1 - m_smoothFactor);
}
else
{
displayBuffer[n] = spectrum[n];
}
}
// Update peak-hold and reference freeze data (using a shared curve).
// Peak hold and freeze can be combined: decay only if not frozen.
// Ref. freeze operates on the (possibly averaged) display buffer.
if (m_controls->m_refFreezeModel.value() && m_freezeRequest)
{
peakBuffer[n] = displayBuffer[n];
}
else if (m_controls->m_peakHoldModel.value() && !m_controls->m_pauseModel.value())
{
if (spectrum[n] > peakBuffer[n])
{
peakBuffer[n] = spectrum[n];
}
else if (!m_controls->m_refFreezeModel.value())
{
peakBuffer[n] = peakBuffer[n] * m_peakDecayFactor;
}
}
else if (!m_controls->m_refFreezeModel.value() && !m_controls->m_peakHoldModel.value())
{
peakBuffer[n] = 0;
}
// take note if there was actually anything to display
m_decaySum += displayBuffer[n] + peakBuffer[n];
}
}
// Use display buffer to build a path that can be drawn or filled by QPainter.
// Resolution controls the performance / quality tradeoff; the value specifies
// number of points in x axis per device pixel. Values over 1.0 still
// contribute to quality and accuracy thanks to anti-aliasing.
QPainterPath SaSpectrumView::makePath(std::vector<float> &displayBuffer, float resolution = 1.0)
{
// convert resolution to number of path points per logical pixel
float pixel_limit = resolution * window()->devicePixelRatio();
QPainterPath path;
path.moveTo(m_displayLeft, m_displayBottom);
// Translate frequency bins to path points.
// Display is flipped: y values grow towards zero, initial max is bottom.
// Bins falling to interval [x_start, x_next) contribute to a single point.
float max = m_displayBottom;
float x_start = -1; // lower bound of currently constructed point
for (unsigned int n = 0; n < m_processor->binCount(); n++)
{
float x = freqToXPixel(binToFreq(n), m_displayWidth);
float x_next = freqToXPixel(binToFreq(n + 1), m_displayWidth);
float y = ampToYPixel(displayBuffer[n], m_displayBottom);
// consider making a point only if x falls within display bounds
if (0 < x && x < m_displayWidth)
{
if (x_start == -1)
{
x_start = x;
// the first displayed bin is stretched to the left edge to prevent
// creating a misleading slope leading to zero (at log. scale)
path.lineTo(m_displayLeft, y + m_displayTop);
}
// Opt.: QPainter is very slow -- draw at most [pixel_limit] points
// per logical pixel. As opposed to limiting the bin count, this
// allows high resolution display if user resizes the analyzer.
// Look at bins that share the pixel and use the highest value:
max = y < max ? y : max;
// And make the final point in the middle of current interval.
if ((int)(x * pixel_limit) != (int)(x_next * pixel_limit))
{
x = (x + x_start) / 2;
path.lineTo(x + m_displayLeft, max + m_displayTop);
max = m_displayBottom;
x_start = x_next;
}
}
else
{
// stop processing after a bin falls outside right edge
// and align it to the edge to prevent a gap
if (n > 0 && x > 0)
{
path.lineTo(m_displayRight, y + m_displayTop);
break;
}
}
}
path.lineTo(m_displayRight, m_displayBottom);
path.closeSubpath();
return path;
}
// Draw background, grid and associated frequency and amplitude labels.
void SaSpectrumView::drawGrid(QPainter &painter)
{
std::vector<std::pair<int, std::string>> *freqTics = NULL;
std::vector<std::pair<float, std::string>> *ampTics = NULL;
float pos = 0;
float label_width = 24;
float label_height = 15;
float margin = 5;
// always draw the background
painter.fillRect(m_displayLeft, m_displayTop,
m_displayWidth, m_displayBottom,
m_controls->m_colorBG);
// select logarithmic or linear frequency grid and draw it
if (m_controls->m_logXModel.value())
{
freqTics = &m_logFreqTics;
}
else
{
freqTics = &m_linearFreqTics;
}
// draw frequency grid (line.first is display position)
painter.setPen(QPen(m_controls->m_colorGrid, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
for (auto &line: *freqTics)
{
painter.drawLine(m_displayLeft + freqToXPixel(line.first, m_displayWidth),
2,
m_displayLeft + freqToXPixel(line.first, m_displayWidth),
m_displayBottom);
}
// print frequency labels (line.second is label)
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
for (auto & line: *freqTics)
{
pos = m_displayLeft + freqToXPixel(line.first, m_displayWidth);
// align first and last label to the edge if needed, otherwise center them
if (line == freqTics->front() && pos - label_width / 2 < m_displayLeft)
{
painter.drawText(m_displayLeft, m_displayBottom + margin,
label_width, label_height, Qt::AlignLeft | Qt::TextDontClip,
QString(line.second.c_str()));
}
else if (line == freqTics->back() && pos + label_width / 2 > m_displayRight)
{
painter.drawText(m_displayRight - label_width, m_displayBottom + margin,
label_width, label_height, Qt::AlignRight | Qt::TextDontClip,
QString(line.second.c_str()));
}
else
{
painter.drawText(pos - label_width / 2, m_displayBottom + margin,
label_width, label_height, Qt::AlignHCenter | Qt::TextDontClip,
QString(line.second.c_str()));
}
}
margin = 2;
// select logarithmic or linear amplitude grid and draw it
if (m_controls->m_logYModel.value())
{
ampTics = &m_logAmpTics;
}
else
{
ampTics = &m_linearAmpTics;
}
// draw amplitude grid
painter.setPen(QPen(m_controls->m_colorGrid, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
for (auto & line: *ampTics)
{
painter.drawLine(m_displayLeft + 1,
ampToYPixel(line.first, m_displayBottom),
m_displayRight - 1,
ampToYPixel(line.first, m_displayBottom));
}
// print amplitude labels
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
bool stereo = m_controls->m_stereoModel.value();
for (auto & line: *ampTics)
{
pos = ampToYPixel(line.first, m_displayBottom);
// align first and last labels to edge if needed, otherwise center them
if (line == ampTics->back() && pos < 8)
{
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorL.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayLeft - label_width - margin, m_displayTop - 2,
label_width, label_height, Qt::AlignRight | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorR.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayRight + margin, m_displayTop - 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
}
else if (line == ampTics->front() && pos > m_displayBottom - label_height)
{
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorL.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayLeft - label_width - margin, m_displayBottom - label_height + 2,
label_width, label_height, Qt::AlignRight | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorR.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayRight + margin, m_displayBottom - label_height + 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
}
else
{
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorL.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayLeft - label_width - margin, pos - label_height / 2,
label_width, label_height, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
if (stereo)
{
painter.setPen(QPen(m_controls->m_colorR.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
}
painter.drawText(m_displayRight + margin, pos - label_height / 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
}
}
}
// Draw cursor and its coordinates if it is within display bounds.
void SaSpectrumView::drawCursor(QPainter &painter)
{
if( m_cursor.x() >= m_displayLeft
&& m_cursor.x() <= m_displayRight
&& m_cursor.y() >= m_displayTop
&& m_cursor.y() <= m_displayBottom)
{
// cursor lines
painter.setPen(QPen(m_controls->m_colorGrid.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawLine(m_cursor.x(), m_displayTop, m_cursor.x(), m_displayBottom);
painter.drawLine(m_displayLeft, m_cursor.y(), m_displayRight, m_cursor.y());
// coordinates
painter.setPen(QPen(m_controls->m_colorLabels.darker(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawText(m_displayRight -60, 5, 100, 16, Qt::AlignLeft, "Cursor");
QString tmps;
// frequency
int xFreq = (int)m_processor->xPixelToFreq(m_cursor.x() - m_displayLeft, m_displayWidth);
tmps = QString(std::string(std::to_string(xFreq) + " Hz").c_str());
painter.drawText(m_displayRight -60, 18, 100, 16, Qt::AlignLeft, tmps);
// amplitude
float yAmp = m_processor->yPixelToAmp(m_cursor.y(), m_displayBottom);
if (m_controls->m_logYModel.value())
{
tmps = QString(std::string(std::to_string(yAmp).substr(0, 5) + " dB").c_str());
}
else
{
// add 0.0005 to get proper rounding to 3 decimal places
tmps = QString(std::string(std::to_string(0.0005f + yAmp)).substr(0, 5).c_str());
}
painter.drawText(m_displayRight -60, 30, 100, 16, Qt::AlignLeft, tmps);
}
}
// Wrappers for most used SaProcessor helpers (to make local code more compact).
float SaSpectrumView::binToFreq(unsigned int bin_index)
{
return m_processor->binToFreq(bin_index);
}
float SaSpectrumView::freqToXPixel(float frequency, unsigned int width)
{
return m_processor->freqToXPixel(frequency, width);
}
float SaSpectrumView::ampToYPixel(float amplitude, unsigned int height)
{
return m_processor->ampToYPixel(amplitude, height);
}
// Generate labels suitable for logarithmic frequency scale.
// Low / high limits are in Hz. Lowest possible label is 10 Hz.
std::vector<std::pair<int, std::string>> SaSpectrumView::makeLogFreqTics(int low, int high)
{
std::vector<std::pair<int, std::string>> result;
int i, j;
int a[] = {10, 20, 50}; // sparse series multipliers
int b[] = {14, 30, 70}; // additional (denser) series
// generate main steps (powers of 10); use the series to specify smaller steps
for (i = 1; i <= high; i *= 10)
{
for (j = 0; j < 3; j++)
{
// insert a label from sparse series if it falls within bounds
if (i * a[j] >= low && i * a[j] <= high)
{
if (i * a[j] < 1000)
{
result.emplace_back(i * a[j], std::to_string(i * a[j]));
}
else
{
result.emplace_back(i * a[j], std::to_string(i * a[j] / 1000) + "k");
}
}
// also insert denser series if high and low values are close
if ((log10(high) - log10(low) < 2) && (i * b[j] >= low && i * b[j] <= high))
{
if (i * b[j] < 1500)
{
result.emplace_back(i * b[j], std::to_string(i * b[j]));
}
else
{
result.emplace_back(i * b[j], std::to_string(i * b[j] / 1000) + "k");
}
}
}
}
return result;
}
// Generate labels suitable for linear frequency scale.
// Low / high limits are in Hz.
std::vector<std::pair<int, std::string>> SaSpectrumView::makeLinearFreqTics(int low, int high)
{
std::vector<std::pair<int, std::string>> result;
int i, increment;
// select a suitable increment based on zoom level
if (high - low < 500) {increment = 50;}
else if (high - low < 1000) {increment = 100;}
else if (high - low < 5000) {increment = 1000;}
else {increment = 2000;}
// generate steps based on increment, starting at 0
for (i = 0; i <= high; i += increment)
{
if (i >= low)
{
if (i < 1000)
{
result.emplace_back(i, std::to_string(i));
}
else
{
result.emplace_back(i, std::to_string(i/1000) + "k");
}
}
}
return result;
}
// Generate labels suitable for logarithmic (dB) amplitude scale.
// Low / high limits are in dB; 0 dB amplitude = 1.0 linear.
// Treating results as power ratio, i.e., 3 dB should be about twice as loud.
std::vector<std::pair<float, std::string>> SaSpectrumView::makeLogAmpTics(int low, int high)
{
std::vector<std::pair<float, std::string>> result;
float i;
double increment;
// Base zoom level on selected range and how close is the current height
// to the sizeHint() (denser scale for bigger window).
if ((high - low) < 20 * ((float)height() / sizeHint().height()))
{
increment = pow(10, 0.3); // 3 dB steps when really zoomed in
}
else if (high - low < 45 * ((float)height() / sizeHint().height()))
{
increment = pow(10, 0.6); // 6 dB steps when sufficiently zoomed in
}
else
{
increment = 10; // 10 dB steps otherwise
}
// Generate n dB increments, start checking at -90 dB. Limits are tweaked
// just a little bit to make sure float comparisons do not miss edges.
for (i = 0.000000001; 10 * log10(i) <= (high + 0.001); i *= increment)
{
if (10 * log10(i) >= (low - 0.001))
{
result.emplace_back(i, std::to_string((int)std::round(10 * log10(i))));
}
}
return result;
}
// Generate labels suitable for linear amplitude scale.
// Low / high limits are in dB; 0 dB amplitude = 1.0 linear.
// Smallest possible label is 0.001, largest is 999. This includes the majority
// of useful labels; going lower or higher would require increasing margin size
// so that the text can fit. That would be a waste of space -- the linear scale
// would only make the experience worse for the main, logarithmic (dB) scale.
std::vector<std::pair<float, std::string>> SaSpectrumView::makeLinearAmpTics(int low, int high)
{
std::vector<std::pair<float, std::string>> result;
double i, nearest;
// make about 5 labels when window is small, 10 if it is big
float split = (float)height() / sizeHint().height() >= 1.5 ? 10.0 : 5.0;
// convert limits to linear scale
float lin_low = pow(10, low / 10.0);
float lin_high = pow(10, high / 10.0);
// Linear scale will vary widely, so instead of trying to craft extra nice
// multiples, just generate a few evenly spaced increments across the range,
// paying attention only to the decimal places to keep labels short.
// Limits are shifted a bit so that float comparisons do not miss edges.
for (i = 0; i <= (lin_high + 0.0001); i += (lin_high - lin_low) / split)
{
if (i >= (lin_low - 0.0001))
{
if (i >= 9.99 && i < 99.9)
{
nearest = std::round(i);
result.emplace_back(nearest, std::to_string(nearest).substr(0, 2));
}
else if (i >= 0.099)
{ // also covers numbers above 100
nearest = std::round(i * 10) / 10;
result.emplace_back(nearest, std::to_string(nearest).substr(0, 3));
}
else if (i >= 0.0099)
{
nearest = std::round(i * 1000) / 1000;
result.emplace_back(nearest, std::to_string(nearest).substr(0, 4));
}
else if (i >= 0.00099)
{
nearest = std::round(i * 10000) / 10000;
result.emplace_back(nearest, std::to_string(nearest).substr(1, 4));
}
else if (i > -0.01 && i < 0.01)
{
result.emplace_back(i, "0"); // an exception, zero is short..
}
}
}
return result;
}
// Periodic update is called by LMMS.
void SaSpectrumView::periodicUpdate()
{
// check if the widget is visible; if it is not, processing can be paused
m_processor->setSpectrumActive(isVisible());
// tell Qt it is time for repaint
update();
}
// Handle mouse input: set new cursor position.
void SaSpectrumView::mouseMoveEvent(QMouseEvent *event)
{
m_cursor = event->pos();
}
void SaSpectrumView::mousePressEvent(QMouseEvent *event)
{
m_cursor = event->pos();
}
// Handle resize event: rebuild grid and labels
void SaSpectrumView::resizeEvent(QResizeEvent *event)
{
// frequency does not change density with size
// amplitude does: rebuild labels
m_logAmpTics = makeLogAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax());
m_linearAmpTics = makeLinearAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax());
}

View File

@@ -0,0 +1,126 @@
/* SaSpectrumView.h - declaration of SaSpectrumView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014 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.
*
*/
#ifndef SASPECTRUMVIEW_H
#define SASPECTRUMVIEW_H
#include <string>
#include <utility>
#include <QPainterPath>
#include <QWidget>
class QMouseEvent;
class QPainter;
class SaControls;
class SaProcessor;
//! Widget that displays a spectrum curve and frequency / amplitude grid
class SaSpectrumView : public QWidget
{
Q_OBJECT
public:
explicit SaSpectrumView(SaControls *controls, SaProcessor *processor, QWidget *_parent = 0);
virtual ~SaSpectrumView() {}
QSize sizeHint() const override {return QSize(400, 200);}
protected:
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private slots:
void periodicUpdate();
private:
const SaControls *m_controls;
SaProcessor *m_processor;
// grid labels (position, label) and methods to generate them
std::vector<std::pair<int, std::string>> m_logFreqTics; // 10-20-50... Hz
std::vector<std::pair<int, std::string>> m_linearFreqTics; // 2k-4k-6k... Hz
std::vector<std::pair<float, std::string>> m_logAmpTics; // dB
std::vector<std::pair<float, std::string>> m_linearAmpTics; // 0..1
std::vector<std::pair<int, std::string>> makeLogFreqTics(int low, int high);
std::vector<std::pair<int, std::string>> makeLinearFreqTics(int low, int high);
std::vector<std::pair<float, std::string>> makeLogAmpTics(int low, int high);
std::vector<std::pair<float, std::string>> makeLinearAmpTics(int low, int high);
// currently selected ranges (see SaControls.h for enum definitions)
int m_freqRangeIndex;
int m_ampRangeIndex;
// draw the grid and all labels based on selected ranges
void drawGrid(QPainter &painter);
// local buffers for frequency bin values and a method to update them
// (mainly needed for averaging and to keep track of peak values)
std::vector<float> m_displayBufferL;
std::vector<float> m_displayBufferR;
std::vector<float> m_peakBufferL;
std::vector<float> m_peakBufferR;
void updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer);
// final paths to be drawn by QPainter and methods to build them
QPainterPath m_pathL;
QPainterPath m_pathR;
QPainterPath m_pathPeakL;
QPainterPath m_pathPeakR;
void refreshPaths();
QPainterPath makePath(std::vector<float> &displayBuffer, float resolution);
// helper variables for path drawing
float m_decaySum; // indicates if there is anything left to draw
bool m_freezeRequest; // new reference should be acquired
bool m_frozen; // a reference is currently stored in the peakBuffer
const float m_smoothFactor = 0.15; // alpha for exponential smoothing
const float m_peakDecayFactor = 0.992; // multiplier for gradual peak decay
// top level: refresh buffers, make paths and draw the spectrum
void drawSpectrum(QPainter &painter);
// current cursor location and a method to draw it
QPoint m_cursor;
void drawCursor(QPainter &painter);
// wrappers for most used SaProcessor conversion helpers
// (to make local code more readable)
float binToFreq(unsigned int bin_index);
float freqToXPixel(float frequency, unsigned int width);
float ampToYPixel(float amplitude, unsigned int height);
// current boundaries for drawing
unsigned int m_displayTop;
unsigned int m_displayBottom;
unsigned int m_displayLeft;
unsigned int m_displayRight;
unsigned int m_displayWidth;
};
#endif // SASPECTRUMVIEW_H

View File

@@ -0,0 +1,230 @@
/* SaWaterfallViewView.cpp - implementation of SaWaterfallViewView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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 "SaWaterfallView.h"
#include <algorithm>
#include <cmath>
#include <QImage>
#include <QMutexLocker>
#include <QPainter>
#include <QSplitter>
#include <QString>
#include "EffectControlDialog.h"
#include "GuiApplication.h"
#include "MainWindow.h"
#include "SaProcessor.h"
SaWaterfallView::SaWaterfallView(SaControls *controls, SaProcessor *processor, QWidget *_parent) :
QWidget(_parent),
m_controls(controls),
m_processor(processor)
{
m_controlDialog = (EffectControlDialog*) _parent;
setMinimumSize(300, 150);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(gui->mainWindow(), SIGNAL(periodicUpdate()), this, SLOT(periodicUpdate()));
m_timeTics = makeTimeTics();
m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate();
}
// Compose and draw all the content; called by Qt.
// Not as performance sensitive as SaSpectrumView, most of the processing is
// done directly in SaProcessor.
void SaWaterfallView::paintEvent(QPaintEvent *event)
{
#ifdef SA_DEBUG
int start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// all drawing done here, local variables are sufficient for the boundary
const int displayTop = 1;
const int displayBottom = height() -2;
const int displayLeft = 26;
const int displayRight = width() -26;
const int displayWidth = displayRight - displayLeft;
float label_width = 20;
float label_height = 16;
float margin = 2;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
// check if time labels need to be rebuilt
if ((float)m_processor->m_inBlockSize / m_processor->getSampleRate() != m_oldTimePerLine)
{
m_timeTics = makeTimeTics();
m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate();
}
// print time labels
float pos = 0;
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
for (auto & line: m_timeTics)
{
pos = timeToYPixel(line.first, displayBottom);
// align first and last label to the edge if needed, otherwise center them
if (line == m_timeTics.front() && pos < label_height / 2)
{
painter.drawText(displayLeft - label_width - margin, displayTop - 1,
label_width, label_height, Qt::AlignRight | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, displayTop - 1,
label_width, label_height, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
}
else if (line == m_timeTics.back() && pos > displayBottom - label_height + 2)
{
painter.drawText(displayLeft - label_width - margin, displayBottom - label_height,
label_width, label_height, Qt::AlignRight | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, displayBottom - label_height + 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
}
else
{
painter.drawText(displayLeft - label_width - margin, pos - label_height / 2,
label_width, label_height, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, pos - label_height / 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
}
}
// draw the spectrogram precomputed in SaProcessor
if (m_processor->m_waterfallNotEmpty)
{
QMutexLocker lock(&m_processor->m_dataAccess);
painter.drawImage(displayLeft, displayTop, // top left corner coordinates
QImage(m_processor->m_history.data(), // raw pixel data to display
m_processor->binCount(), // width = number of frequency bins
m_processor->m_waterfallHeight, // height = number of history lines
QImage::Format_RGB32
).scaled(displayWidth, // scale to fit view..
displayBottom,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
lock.unlock();
}
else
{
painter.fillRect(displayLeft, displayTop, displayWidth, displayBottom, QColor(0,0,0));
}
// always draw the outline
painter.setPen(QPen(m_controls->m_colorGrid, 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawRoundedRect(displayLeft, displayTop, displayWidth, displayBottom, 2.0, 2.0);
#ifdef SA_DEBUG
// display what FPS would be achieved if waterfall ran in a loop
start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - start_time;
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawText(displayRight -100, 10, 100, 16, Qt::AlignLeft,
QString(std::string("Max FPS: " + std::to_string(1000000000.0 / start_time)).c_str()));
#endif
}
// 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 seconds_per_line = ((float)m_processor->m_inBlockSize / m_processor->getSampleRate());
return pixels_per_line * time / seconds_per_line;
}
// Generate labels for linear time scale.
std::vector<std::pair<float, std::string>> SaWaterfallView::makeTimeTics()
{
std::vector<std::pair<float, std::string>> result;
float i;
// upper limit defined by number of lines * time per line
float limit = m_processor->m_waterfallHeight * ((float)m_processor->m_inBlockSize / m_processor->getSampleRate());
// set increment so that about 8 tics are generated
float increment = std::round(10 * limit / 7) / 10;
// NOTE: labels positions are rounded to match the (rounded) label value
for (i = 0; i <= limit; i += increment)
{
if (i < 10)
{
result.emplace_back(std::round(i * 10) / 10, std::to_string(std::round(i * 10) / 10).substr(0, 3));
}
else
{
result.emplace_back(std::round(i), std::to_string(std::round(i)).substr(0, 2));
}
}
return result;
}
// Periodically trigger repaint and check if the widget is visible.
// If it is not, stop drawing and inform the processor.
void SaWaterfallView::periodicUpdate()
{
m_processor->setWaterfallActive(isVisible());
if (isVisible()) {update();}
}
// Adjust window size and widget visibility when waterfall is enabled or disabbled.
void SaWaterfallView::updateVisibility()
{
// get container of the control dialog to be resized if needed
QWidget *subWindow = m_controlDialog->parentWidget();
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.begin(), m_processor->m_history.end(), 0);
lock.unlock();
setVisible(true);
// increase window size if it is too small
if (subWindow->size().height() < m_controlDialog->sizeHint().height())
{
subWindow->resize(subWindow->size().width(), m_controlDialog->sizeHint().height());
}
}
else
{
setVisible(false);
// decrease window size only if it does not violate sizeHint
subWindow->resize(subWindow->size().width(), m_controlDialog->sizeHint().height());
}
}

View File

@@ -0,0 +1,66 @@
/* SaWaterfallView.h - declaration of SaWaterfallView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/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.
*
*/
#ifndef SAWATERFALLVIEW_H
#define SAWATERFALLVIEW_H
#include <string>
#include <utility>
#include <vector>
#include <QPainter>
#include <QWidget>
#include "SaControls.h"
#include "SaProcessor.h"
// Widget that displays a spectrum waterfall (spectrogram) and time labels.
class SaWaterfallView : public QWidget
{
Q_OBJECT
public:
explicit SaWaterfallView(SaControls *controls, SaProcessor *processor, QWidget *_parent = 0);
virtual ~SaWaterfallView() {}
QSize sizeHint() const override {return QSize(400, 350);}
// Check if waterfall should be displayed and adjust window size if needed.
void updateVisibility();
protected:
void paintEvent(QPaintEvent *event) override;
private slots:
void periodicUpdate();
private:
const SaControls *m_controls;
SaProcessor *m_processor;
const EffectControlDialog *m_controlDialog;
// Methods and data used to make time labels
float m_oldTimePerLine;
float timeToYPixel(float time, int height);
std::vector<std::pair<float, std::string>> makeTimeTics();
std::vector<std::pair<float, std::string>> m_timeTics; // 0..n (s)
};
#endif // SAWATERFALLVIEW_H

View File

@@ -1,172 +0,0 @@
/*
* SpectrumAnalyzer.cpp - spectrum analyzer effect plugin
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 "SpectrumAnalyzer.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{
Plugin::Descriptor PLUGIN_EXPORT spectrumanalyzer_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"Spectrum Analyzer",
QT_TRANSLATE_NOOP( "pluginBrowser", "Graphical spectrum analyzer plugin" ),
"Tobias Doerffel <tobydox/at/users.sf.net>",
0x0100,
Plugin::Effect,
new PluginPixmapLoader(),
NULL,
NULL
} ;
}
SpectrumAnalyzer::SpectrumAnalyzer( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key ) :
Effect( &spectrumanalyzer_plugin_descriptor, _parent, _key ),
m_saControls( this ),
m_framesFilledUp( 0 ),
m_energy( 0 )
{
memset( m_buffer, 0, sizeof( m_buffer ) );
m_specBuf = (fftwf_complex *) fftwf_malloc( ( FFT_BUFFER_SIZE + 1 ) * sizeof( fftwf_complex ) );
m_fftPlan = fftwf_plan_dft_r2c_1d( FFT_BUFFER_SIZE*2, m_buffer, m_specBuf, FFTW_MEASURE );
}
SpectrumAnalyzer::~SpectrumAnalyzer()
{
fftwf_destroy_plan( m_fftPlan );
fftwf_free( m_specBuf );
}
bool SpectrumAnalyzer::processAudioBuffer( sampleFrame* _buf, const fpp_t _frames )
{
if( !isEnabled() || !isRunning () )
{
return false;
}
if( !m_saControls.isViewVisible() )
{
return true;
}
fpp_t f = 0;
if( _frames > FFT_BUFFER_SIZE )
{
m_framesFilledUp = 0;
f = _frames - FFT_BUFFER_SIZE;
}
const int cm = m_saControls.m_channelMode.value();
switch( cm )
{
case MergeChannels:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] =
( _buf[f][0] + _buf[f][1] ) * 0.5;
++m_framesFilledUp;
}
break;
case LeftChannel:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] = _buf[f][0];
++m_framesFilledUp;
}
break;
case RightChannel:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] = _buf[f][1];
++m_framesFilledUp;
}
break;
}
if( m_framesFilledUp < FFT_BUFFER_SIZE )
{
return isRunning();
}
// hanming( m_buffer, FFT_BUFFER_SIZE, HAMMING );
const sample_rate_t sr = Engine::mixer()->processingSampleRate();
const int LOWEST_FREQ = 0;
const int HIGHEST_FREQ = sr / 2;
fftwf_execute( m_fftPlan );
absspec( m_specBuf, m_absSpecBuf, FFT_BUFFER_SIZE+1 );
if( m_saControls.m_linearSpec.value() )
{
compressbands( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1,
MAX_BANDS,
(int)(LOWEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2)),
(int)(HIGHEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2)));
m_energy = maximum( m_bands, MAX_BANDS ) / maximum( m_buffer, FFT_BUFFER_SIZE );
}
else
{
calc13octaveband31( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1, sr/2.0 );
m_energy = signalpower( m_buffer, FFT_BUFFER_SIZE ) / maximum( m_buffer, FFT_BUFFER_SIZE );
}
m_framesFilledUp = 0;
checkGate( 1 );
return isRunning();
}
extern "C"
{
// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
return new SpectrumAnalyzer( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}
}

View File

@@ -1,78 +0,0 @@
/*
* SpectrumAnalyzer.h - spectrum anaylzer effect plugin
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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.
*
*/
#ifndef _SPECTRUM_ANALYZER_H
#define _SPECTRUM_ANALYZER_H
#include "Effect.h"
#include "fft_helpers.h"
#include "SpectrumAnalyzerControls.h"
const int MAX_BANDS = 249;
class SpectrumAnalyzer : public Effect
{
public:
enum ChannelModes
{
MergeChannels,
LeftChannel,
RightChannel
} ;
SpectrumAnalyzer( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key );
virtual ~SpectrumAnalyzer();
virtual bool processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames );
virtual EffectControls * controls()
{
return( &m_saControls );
}
private:
SpectrumAnalyzerControls m_saControls;
fftwf_plan m_fftPlan;
fftwf_complex * m_specBuf;
float m_absSpecBuf[FFT_BUFFER_SIZE+1];
float m_buffer[FFT_BUFFER_SIZE*2];
int m_framesFilledUp;
float m_bands[MAX_BANDS];
float m_energy;
friend class SpectrumAnalyzerControls;
friend class SpectrumView;
} ;
#endif

View File

@@ -1,194 +0,0 @@
/*
* SpectrumAnalyzerControlDialog.cpp - view for spectrum analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <cmath>
#include <QLayout>
#include <QPainter>
#include "SpectrumAnalyzer.h"
#include "MainWindow.h"
#include "GuiApplication.h"
#include "LedCheckbox.h"
#include "embed.h"
static inline void darken( QImage& img, int x, int y, int w, int h )
{
int imgWidth = img.width();
QRgb * base = ( (QRgb *) img.bits() ) + y*imgWidth + x;
for( int y = 0; y < h; ++y )
{
QRgb * d = base + y*imgWidth;
for( int x = 0; x < w; ++x )
{
// shift each color component by 1 bit and set alpha
// to 0xff
d[x] = ( ( d[x] >> 1 ) & 0x7f7f7f7f ) | 0xff000000;
}
}
}
class SpectrumView : public QWidget
{
public:
SpectrumView( SpectrumAnalyzer* s, QWidget * _parent ) :
QWidget( _parent ),
m_sa( s ),
m_backgroundPlain( PLUGIN_NAME::getIconPixmap( "spectrum_background_plain" ).toImage() ),
m_background( PLUGIN_NAME::getIconPixmap( "spectrum_background" ).toImage() )
{
setFixedSize( 249, 151 );
connect( gui->mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
setAttribute( Qt::WA_OpaquePaintEvent, true );
}
virtual ~SpectrumView()
{
}
virtual void paintEvent( QPaintEvent* event )
{
QPainter p( this );
QImage i = m_sa->m_saControls.m_linearSpec.value() ?
m_backgroundPlain : m_background;
const float e = m_sa->m_energy;
if( e <= 0 )
{
darken( i, 0, 0, i.width(), i.height() );
p.drawImage( 0, 0, i );
return;
}
const bool lin_y = m_sa->m_saControls.m_linearYAxis.value();
float * b = m_sa->m_bands;
const int LOWER_Y = -60; // dB
int h;
const int fh = height();
if( m_sa->m_saControls.m_linearSpec.value() )
{
if( lin_y )
{
for( int x = 0; x < MAX_BANDS; ++x, ++b )
{
h = fh * 2.0 / 3.0 * (*b / e );
if( h < 0 ) h = 0; else if( h >= fh ) continue;
darken( i, x, 0, 1, fh-h );
}
}
else
{
for( int x = 0; x < MAX_BANDS; ++x, ++b )
{
h = (int)( fh * 2.0 / 3.0 * (20*(log10( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) );
if( h < 0 ) h = 0; else if( h >= fh ) continue;
darken( i, x, 0, 1, fh-h );
}
}
}
else
{
if( lin_y )
{
for( int x = 0; x < 31; ++x, ++b )
{
h = fh * 2.0 / 3.0 * ( 1.2 * *b / e );
if( h < 0 ) h = 0; else if( h >= fh ) continue; else h = ( h / 3 ) * 3;
darken( i, x*8, 0, 8, fh-h );
}
}
else
{
for( int x = 0; x < 31; ++x, ++b )
{
h = (int)( fh * 2.0 / 3.0 * (20*(log10( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) );
if( h < 0 ) h = 0; else if( h >= fh ) continue; else h = ( h / 3 ) * 3;
darken( i, x*8, 0, 8, fh-h );
}
}
darken( i, 31*8, 0, 1, fh );
}
p.drawImage( 0, 0, i );
}
private:
SpectrumAnalyzer * m_sa;
QImage m_backgroundPlain;
QImage m_background;
} ;
SpectrumAnalyzerControlDialog::SpectrumAnalyzerControlDialog( SpectrumAnalyzerControls* controls ) :
EffectControlDialog( controls ),
m_controls( controls ),
m_logXAxis( PLUGIN_NAME::getIconPixmap( "log_x_axis" ) ),
m_logYAxis( PLUGIN_NAME::getIconPixmap( "log_y_axis" ) )
{
setAutoFillBackground( true );
QPalette pal;
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "background" ) );
setFixedSize( 293, 205 );
setPalette( pal );
/* QVBoxLayout * l = new QVBoxLayout( this );*/
SpectrumView* v = new SpectrumView( controls->m_effect, this );
v->move( 34, 10 );
LedCheckBox * lin_spec = new LedCheckBox( tr( "Linear spectrum" ), this );
lin_spec->move( 32, 182 );
lin_spec->setModel( &controls->m_linearSpec );
LedCheckBox * lin_y = new LedCheckBox( tr( "Linear Y axis" ), this );
lin_y->move( 137, 182 );
lin_y->setModel( &controls->m_linearYAxis );
connect( &controls->m_linearSpec, SIGNAL( dataChanged() ), this, SLOT( update() ) );
connect( &controls->m_linearYAxis, SIGNAL( dataChanged() ), this, SLOT( update() ) );
/* l->addWidget( v );
l->addWidget( lin_spec );
l->addWidget( lin_y );*/
}
void SpectrumAnalyzerControlDialog::paintEvent( QPaintEvent * )
{
QPainter p( this );
if( !m_controls->m_linearSpec.value() )
{
p.drawPixmap( 33, 165, m_logXAxis );
}
if( !m_controls->m_linearYAxis.value() )
{
p.drawPixmap( 10, 29, m_logYAxis);
}
}

View File

@@ -1,61 +0,0 @@
/*
* SpectrumAnalyzerControls.cpp - controls for spectrum analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 "SpectrumAnalyzer.h"
#include "SpectrumAnalyzerControls.h"
SpectrumAnalyzerControls::SpectrumAnalyzerControls( SpectrumAnalyzer* effect ) :
EffectControls( effect ),
m_effect( effect ),
m_linearSpec( false, this, tr( "Linear spectrum" ) ),
m_linearYAxis( false, this, tr( "Linear Y axis" ) ),
m_channelMode( SpectrumAnalyzer::MergeChannels,
SpectrumAnalyzer::MergeChannels,
SpectrumAnalyzer::RightChannel,
this, tr( "Channel mode" ) )
{
}
void SpectrumAnalyzerControls::loadSettings( const QDomElement & _this )
{
}
void SpectrumAnalyzerControls::saveSettings( QDomDocument & _doc,
QDomElement & _this )
{
}

View File

@@ -1,75 +0,0 @@
/*
* SpectrumAnalyzerControls.h - controls for spectrum-analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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.
*
*/
#ifndef SPECTRUM_ANALYZER_CONTROLS_H
#define SPECTRUM_ANALYZER_CONTROLS_H
#include "EffectControls.h"
#include "SpectrumAnalyzerControlDialog.h"
#include "Knob.h"
class SpectrumAnalyzer;
class SpectrumAnalyzerControls : public EffectControls
{
Q_OBJECT
public:
SpectrumAnalyzerControls( SpectrumAnalyzer* effect );
virtual ~SpectrumAnalyzerControls()
{
}
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
virtual void loadSettings( const QDomElement & _this );
inline virtual QString nodeName() const
{
return "spectrumanaylzercontrols";
}
virtual int controlCount()
{
return 1;
}
virtual EffectControlDialog * createView()
{
return new SpectrumAnalyzerControlDialog( this );
}
private:
SpectrumAnalyzer* m_effect;
BoolModel m_linearSpec;
BoolModel m_linearYAxis;
IntModel m_channelMode;
friend class SpectrumAnalyzer;
friend class SpectrumAnalyzerControlDialog;
friend class SpectrumView;
} ;
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 859 B

View File

@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="block_size.svg.2019_03_31_01_06_33.0.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="TriangleOutM"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path8579"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="TriangleInM"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path8570"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="154.07316"
inkscape:cy="214.45272"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<path
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 72.999999,117 v 80"
id="path8424"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path8426"
d="m 148,117 v 80"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInM);marker-end:url(#TriangleOutM)"
d="M 87.113439,142.15138 H 133.56041"
id="path8432"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path9420"
d="m 79.86528,184.07963 h 62.36081"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4.09999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.10000002, 4.10000002;stroke-dashoffset:0;stroke-opacity:1" />
<g
id="g8730">
<path
id="path8736"
d="m 77.881439,142.15138 13.84,-8 v 16 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.60000008pt;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path8738"
d="m 142.79241,142.15138 -13.84,8 v -16 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.60000008pt;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -0,0 +1,296 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="freeze.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="61.391665"
inkscape:cy="165.33406"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="false"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-center="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<path
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 110,117 v 80"
id="path8424"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path8426"
d="M 75.358985,177 144.64101,137"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path8591"
d="M 144.64101,177 75.358984,137"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
id="g8599">
<path
inkscape:transform-center-x="6.9453125"
inkscape:transform-center-y="-6.9453101"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 97.160779,123.8149 12.846151,12.84614"
id="path8593"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path8595"
d="m 122.83921,123.8149 -12.84614,12.84614"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="-6.9453101"
inkscape:transform-center-x="-6.94531"
sodipodi:nodetypes="cc" />
</g>
<use
x="0"
y="0"
xlink:href="#g8599"
id="use8515"
inkscape:transform-center-y="-17.121722"
width="100%"
height="100%"
transform="rotate(60,110,157)"
inkscape:transform-center-x="-27.10753" />
<use
x="0"
y="0"
xlink:href="#use8515"
inkscape:transform-center-x="-27.107531"
inkscape:transform-center-y="17.121718"
id="use8517"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8517"
inkscape:transform-center-x="-4.7502381e-06"
inkscape:transform-center-y="27.2912"
id="use8519"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8519"
inkscape:transform-center-x="27.107525"
inkscape:transform-center-y="17.121722"
id="use8521"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8521"
inkscape:transform-center-x="27.107527"
inkscape:transform-center-y="-17.121718"
id="use8523"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,297 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="freeze_off.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="54.320595"
inkscape:cy="173.66782"
inkscape:document-units="mm"
inkscape:current-layer="g8599"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="false"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-center="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<path
style="fill:none;fill-rule:evenodd;stroke:#8a8e96;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 110,117 v 80"
id="path8424"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path8426"
d="M 75.358985,177 144.64101,137"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8a8e96;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path8591"
d="M 144.64101,177 75.358984,137"
style="fill:none;fill-rule:evenodd;stroke:#8a8e96;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
id="g8599"
style="stroke:#8a8e96;stroke-opacity:1">
<path
inkscape:transform-center-x="6.9453125"
inkscape:transform-center-y="-6.9453101"
style="fill:none;fill-rule:evenodd;stroke:#8a8e96;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 97.160779,123.8149 12.846151,12.84614"
id="path8593"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path8595"
d="m 122.83921,123.8149 -12.84614,12.84614"
style="fill:none;fill-rule:evenodd;stroke:#8a8e96;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="-6.9453101"
inkscape:transform-center-x="-6.94531"
sodipodi:nodetypes="cc" />
</g>
<use
x="0"
y="0"
xlink:href="#g8599"
id="use8515"
inkscape:transform-center-y="-16.857138"
width="100%"
height="100%"
transform="rotate(60,110,157)"
inkscape:transform-center-x="-26.746102" />
<use
x="0"
y="0"
xlink:href="#use8515"
inkscape:transform-center-x="-26.746104"
inkscape:transform-center-y="16.857132"
id="use8517"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8517"
inkscape:transform-center-x="-8.3316985e-06"
inkscape:transform-center-y="27.026615"
id="use8519"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8519"
inkscape:transform-center-x="26.746093"
inkscape:transform-center-y="16.857138"
id="use8521"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8521"
inkscape:transform-center-x="26.746095"
inkscape:transform-center-y="-16.857132"
id="use8523"
transform="rotate(60,110,157)"
width="100%"
height="100%" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

View File

@@ -0,0 +1,220 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="pause.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.5247505"
inkscape:cx="186.56659"
inkscape:cy="175.68099"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<path
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:18;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 88.874998,122 v 70"
id="path8424"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path8426"
d="m 132.12499,122 v 70"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:18;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="play.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="71.366921"
inkscape:cy="213.56884"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<g
id="g8730"
transform="translate(0,-10.583333)">
<path
id="path8738"
d="m 140.92066,167.57847 -63.353995,35.67994 v -71.3599 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.60000008pt;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

View File

@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="99.73542mm"
height="99.73542mm"
viewBox="0 0 99.73542 99.73542"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="window.svg"
inkscape:export-filename="/home/martin/projects/software/lmms/plugins/SpectrumAnalyzer/window.svg.png"
inkscape:export-xdpi="16.299124"
inkscape:export-ydpi="16.299124">
<defs
id="defs2">
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="TriangleOutM"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8579"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="TriangleInM"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8570"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="64.760601"
inkscape:cy="152.43979"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-60.13229,-107.13229)">
<path
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 72.999999,117 v 80"
id="path8424"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path8426"
d="m 148,117 v 80"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 73.884273,181.83888 c 0,0 12.89641,-6.08542 18.543384,-20.6375 5.646974,-14.55209 7.824273,-34.925 17.909263,-34.925 10.08499,0 12.2623,20.37291 17.90927,34.925 5.64698,14.55208 18.54338,20.6375 18.54338,20.6375"
id="path8432"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cszsc" />
<path
inkscape:connector-curvature="0"
id="path9420"
d="M 79.675577,184.07963 H 142.5001"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4.0999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.1, 4.1;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -0,0 +1,242 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="x_linear.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-138.52362"
inkscape:cy="185.47638"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<g
aria-label="X"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8591"
transform="translate(0,-1.0583333)">
<path
d="M 116.01015,174.93644 127.60979,192 h -8.97964 L 110.81495,180.57951 103.06693,192 H 94.0425 l 11.59964,-17.06356 -11.151777,-16.36937 h 9.002037 l 7.32255,10.77109 7.30015,-10.77109 h 9.04683 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:45.86111069px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path8505"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(-2.39e-4,-3.2244934)"
aria-label="LOG"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';letter-spacing:0px;word-spacing:0px;fill:#8a8e96;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8595-3">
<path
inkscape:connector-curvature="0"
d="m 77.419237,123.94899 h 5.977241 v 20.70502 h 10.47309 v 5.01262 H 77.419237 Z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26803" />
<path
inkscape:connector-curvature="0"
d="m 107.01261,128.28981 q -2.72163,0 -4.23747,2.23931 -1.49862,2.23931 -1.49862,6.30452 0,4.04799 1.49862,6.2873 1.51584,2.23932 4.23747,2.23932 2.73885,0 4.23747,-2.23932 1.51584,-2.23931 1.51584,-6.2873 0,-4.06521 -1.51584,-6.30452 -1.49862,-2.23931 -4.23747,-2.23931 z m 0,-4.80591 q 5.58105,0 8.73332,3.54845 3.16948,3.54845 3.16948,9.80129 0,6.23563 -3.16948,9.78408 -3.15227,3.54844 -8.73332,3.54844 -5.56383,0 -8.733319,-3.54844 -3.169488,-3.54845 -3.169488,-9.78408 0,-6.25284 3.169488,-9.80129 3.169489,-3.54845 8.733319,-3.54845 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26805" />
<path
inkscape:connector-curvature="0"
d="m 144.25409,147.7546 q -2.23931,1.20578 -4.65088,1.80867 -2.39434,0.60289 -4.94371,0.60289 -5.78776,0 -9.16395,-3.58289 -3.3762,-3.60013 -3.3762,-9.74963 0,-6.21839 3.42787,-9.78407 3.4451,-3.56567 9.43956,-3.56567 2.30822,0 4.42695,0.48231 2.11874,0.48232 3.99631,1.42972 v 5.32267 q -1.94648,-1.22301 -3.8585,-1.8259 -1.91203,-0.60289 -3.84128,-0.60289 -3.56568,0 -5.49493,2.22208 -1.92926,2.20487 -1.92926,6.32175 0,4.08244 1.86036,6.30453 1.86035,2.22209 5.28822,2.22209 0.93017,0 1.72255,-0.12058 0.80959,-0.13781 1.42971,-0.41341 v -4.99539 h -3.63458 v -4.44418 h 9.30176 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26807" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="x_log.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-140.02362"
inkscape:cy="188.97638"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<g
aria-label="LOG"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8595"
transform="translate(0,-3.2244934)">
<path
d="m 77.419237,123.94899 h 5.977241 v 20.70502 h 10.47309 v 5.01262 H 77.419237 Z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path26796"
inkscape:connector-curvature="0" />
<path
d="m 107.01261,128.28981 q -2.72163,0 -4.23747,2.23931 -1.49862,2.23931 -1.49862,6.30452 0,4.04799 1.49862,6.2873 1.51584,2.23932 4.23747,2.23932 2.73885,0 4.23747,-2.23932 1.51584,-2.23931 1.51584,-6.2873 0,-4.06521 -1.51584,-6.30452 -1.49862,-2.23931 -4.23747,-2.23931 z m 0,-4.80591 q 5.58105,0 8.73332,3.54845 3.16948,3.54845 3.16948,9.80129 0,6.23563 -3.16948,9.78408 -3.15227,3.54844 -8.73332,3.54844 -5.56383,0 -8.733319,-3.54844 -3.169488,-3.54845 -3.169488,-9.78408 0,-6.25284 3.169488,-9.80129 3.169489,-3.54845 8.733319,-3.54845 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path26798"
inkscape:connector-curvature="0" />
<path
d="m 144.25409,147.7546 q -2.23931,1.20578 -4.65088,1.80867 -2.39434,0.60289 -4.94371,0.60289 -5.78776,0 -9.16395,-3.58289 -3.3762,-3.60013 -3.3762,-9.74963 0,-6.21839 3.42787,-9.78407 3.4451,-3.56567 9.43956,-3.56567 2.30822,0 4.42695,0.48231 2.11874,0.48232 3.99631,1.42972 v 5.32267 q -1.94648,-1.22301 -3.8585,-1.8259 -1.91203,-0.60289 -3.84128,-0.60289 -3.56568,0 -5.49493,2.22208 -1.92926,2.20487 -1.92926,6.32175 0,4.08244 1.86036,6.30453 1.86035,2.22209 5.28822,2.22209 0.93017,0 1.72255,-0.12058 0.80959,-0.13781 1.42971,-0.41341 v -4.99539 h -3.63458 v -4.44418 h 9.30176 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path26800"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="X"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8591"
transform="translate(0,-1.0583333)">
<path
d="M 116.01015,174.93644 127.60979,192 h -8.97964 L 110.81495,180.57951 103.06693,192 H 94.0425 l 11.59964,-17.06356 -11.151777,-16.36937 h 9.002037 l 7.32255,10.77109 7.30015,-10.77109 h 9.04683 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:45.86111069px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path35945"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="y_linear.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-140.02362"
inkscape:cy="188.97638"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<g
aria-label="LOG"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';letter-spacing:0px;word-spacing:0px;fill:#8a8e96;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8595"
transform="translate(-2.39e-4,-3.2244934)">
<path
d="m 77.419237,123.94899 h 5.977241 v 20.70502 h 10.47309 v 5.01262 H 77.419237 Z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26803"
inkscape:connector-curvature="0" />
<path
d="m 107.01261,128.28981 q -2.72163,0 -4.23747,2.23931 -1.49862,2.23931 -1.49862,6.30452 0,4.04799 1.49862,6.2873 1.51584,2.23932 4.23747,2.23932 2.73885,0 4.23747,-2.23932 1.51584,-2.23931 1.51584,-6.2873 0,-4.06521 -1.51584,-6.30452 -1.49862,-2.23931 -4.23747,-2.23931 z m 0,-4.80591 q 5.58105,0 8.73332,3.54845 3.16948,3.54845 3.16948,9.80129 0,6.23563 -3.16948,9.78408 -3.15227,3.54844 -8.73332,3.54844 -5.56383,0 -8.733319,-3.54844 -3.169488,-3.54845 -3.169488,-9.78408 0,-6.25284 3.169488,-9.80129 3.169489,-3.54845 8.733319,-3.54845 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26805"
inkscape:connector-curvature="0" />
<path
d="m 144.25409,147.7546 q -2.23931,1.20578 -4.65088,1.80867 -2.39434,0.60289 -4.94371,0.60289 -5.78776,0 -9.16395,-3.58289 -3.3762,-3.60013 -3.3762,-9.74963 0,-6.21839 3.42787,-9.78407 3.4451,-3.56567 9.43956,-3.56567 2.30822,0 4.42695,0.48231 2.11874,0.48232 3.99631,1.42972 v 5.32267 q -1.94648,-1.22301 -3.8585,-1.8259 -1.91203,-0.60289 -3.84128,-0.60289 -3.56568,0 -5.49493,2.22208 -1.92926,2.20487 -1.92926,6.32175 0,4.08244 1.86036,6.30453 1.86035,2.22209 5.28822,2.22209 0.93017,0 1.72255,-0.12058 0.80959,-0.13781 1.42971,-0.41341 v -4.99539 h -3.63458 v -4.44418 h 9.30176 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#8a8e96;fill-opacity:1;stroke-width:0.26458332px"
id="path26807"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="Y"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8591"
transform="translate(0,-1.0583333)">
<path
d="m 93.796176,158.56707 h 9.427504 l 7.61366,11.91314 7.61366,-11.91314 h 9.4499 l -12.74169,19.34766 V 192 h -8.62135 v -14.08527 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:45.86111069px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path35942"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="y_log.svg">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8614"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8612" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8538"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8536" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9923"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9921"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8461"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8458"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9470"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Send">
<path
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9468"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9424"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9422"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8440"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8576"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8567"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-140.02362"
inkscape:cy="188.97638"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.999998,-107)">
<g
aria-label="LOG"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8595"
transform="translate(0,-3.2244934)">
<path
d="m 77.419237,123.94899 h 5.977241 v 20.70502 h 10.47309 v 5.01262 H 77.419237 Z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:0.26458332px"
id="path17641"
inkscape:connector-curvature="0" />
<path
d="m 107.01261,128.28981 q -2.72163,0 -4.23747,2.23931 -1.49862,2.23931 -1.49862,6.30452 0,4.04799 1.49862,6.2873 1.51584,2.23932 4.23747,2.23932 2.73885,0 4.23747,-2.23932 1.51584,-2.23931 1.51584,-6.2873 0,-4.06521 -1.51584,-6.30452 -1.49862,-2.23931 -4.23747,-2.23931 z m 0,-4.80591 q 5.58105,0 8.73332,3.54845 3.16948,3.54845 3.16948,9.80129 0,6.23563 -3.16948,9.78408 -3.15227,3.54844 -8.73332,3.54844 -5.56383,0 -8.733319,-3.54844 -3.169488,-3.54845 -3.169488,-9.78408 0,-6.25284 3.169488,-9.80129 3.169489,-3.54845 8.733319,-3.54845 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:0.26458332px"
id="path17643"
inkscape:connector-curvature="0" />
<path
d="m 144.25409,147.7546 q -2.23931,1.20578 -4.65088,1.80867 -2.39434,0.60289 -4.94371,0.60289 -5.78776,0 -9.16395,-3.58289 -3.3762,-3.60013 -3.3762,-9.74963 0,-6.21839 3.42787,-9.78407 3.4451,-3.56567 9.43956,-3.56567 2.30822,0 4.42695,0.48231 2.11874,0.48232 3.99631,1.42972 v 5.32267 q -1.94648,-1.22301 -3.8585,-1.8259 -1.91203,-0.60289 -3.84128,-0.60289 -3.56568,0 -5.49493,2.22208 -1.92926,2.20487 -1.92926,6.32175 0,4.08244 1.86036,6.30453 1.86035,2.22209 5.28822,2.22209 0.93017,0 1.72255,-0.12058 0.80959,-0.13781 1.42971,-0.41341 v -4.99539 h -3.63458 v -4.44418 h 9.30176 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:semi-condensed;font-size:35.27777863px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold Semi-Condensed';text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:0.26458332px"
id="path17645"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="Y"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76388884px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text8591"
transform="translate(0,-1.0583333)">
<path
d="m 93.796176,158.56707 h 9.427504 l 7.61366,11.91314 7.61366,-11.91314 h 9.4499 l -12.74169,19.34766 V 192 h -8.62135 v -14.08527 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:45.86111069px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold';text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332px"
id="path17638"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -274,7 +274,7 @@ public:
XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
InstrumentView(_instrument, _parent)
InstrumentViewFixedSize(_instrument, _parent)
{
const int COL_KNOBS = 194;

View File

@@ -139,7 +139,7 @@ private:
} ;
class XpressiveView : public InstrumentView
class XpressiveView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -449,7 +449,7 @@ QPixmap * AudioFileProcessorView::s_artwork = NULL;
AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
if( s_artwork == NULL )
{

View File

@@ -111,7 +111,7 @@ private:
class AudioFileProcessorWaveView;
class AudioFileProcessorView : public InstrumentView
class AudioFileProcessorView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -326,7 +326,7 @@ PluginView * bitInvader::instantiateView( QWidget * _parent )
bitInvaderView::bitInvaderView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );
QPalette pal;

View File

@@ -108,7 +108,7 @@ private:
class bitInvaderView : public InstrumentView
class bitInvaderView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -460,7 +460,7 @@ void CarlaInstrument::sampleRateChanged()
// -------------------------------------------------------------------
CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWidget* const parent)
: InstrumentView(instrument, parent),
: InstrumentViewFixedSize(instrument, parent),
fHandle(instrument->fHandle),
fDescriptor(instrument->fDescriptor),
fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(30) : 0)

View File

@@ -99,7 +99,7 @@ private:
friend class CarlaInstrumentView;
};
class CarlaInstrumentView : public InstrumentView
class CarlaInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT

View File

@@ -267,7 +267,7 @@ public:
kickerInstrumentView::kickerInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
const int ROW1 = 14;
const int ROW2 = ROW1 + 56;

View File

@@ -94,7 +94,7 @@ private:
class kickerInstrumentView : public InstrumentView
class kickerInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -803,7 +803,7 @@ PluginView * lb302Synth::instantiateView( QWidget * _parent )
lb302SynthView::lb302SynthView( Instrument * _instrument, QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
// GUI
m_vcfCutKnob = new Knob( knobBright_26, this );

View File

@@ -256,7 +256,7 @@ private:
} ;
class lb302SynthView : public InstrumentView
class lb302SynthView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -1447,7 +1447,7 @@ void MonstroInstrument::updateSlope2()
MonstroView::MonstroView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
m_operatorsView = setupOperatorsView( this );
setWidgetBackground( m_operatorsView, "artwork_op" );

View File

@@ -569,7 +569,7 @@ private:
};
class MonstroView : public InstrumentView
class MonstroView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -731,7 +731,7 @@ QPixmap * NesInstrumentView::s_artwork = NULL;
NesInstrumentView::NesInstrumentView( Instrument * instrument, QWidget * parent ) :
InstrumentView( instrument, parent )
InstrumentViewFixedSize( instrument, parent )
{
setAutoFillBackground( true );
QPalette pal;

View File

@@ -294,7 +294,7 @@ private:
};
class NesInstrumentView : public InstrumentView
class NesInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -417,7 +417,7 @@ public:
organicInstrumentView::organicInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent ),
InstrumentViewFixedSize( _instrument, _parent ),
m_oscKnobs( NULL )
{
organicInstrument * oi = castModel<organicInstrument>();

View File

@@ -173,7 +173,7 @@ private slots:
} ;
class organicInstrumentView : public InstrumentView
class organicInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -443,7 +443,7 @@ PluginView * patmanInstrument::instantiateView( QWidget * _parent )
PatmanView::PatmanView( Instrument * _instrument, QWidget * _parent ) :
InstrumentView( _instrument, _parent ),
InstrumentViewFixedSize( _instrument, _parent ),
m_pi( NULL )
{
setAutoFillBackground( true );

View File

@@ -116,7 +116,7 @@ signals:
class PatmanView : public InstrumentView
class PatmanView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -859,7 +859,7 @@ public:
sf2InstrumentView::sf2InstrumentView( Instrument * _instrument, QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
// QVBoxLayout * vl = new QVBoxLayout( this );
// QHBoxLayout * hl = new QHBoxLayout();

View File

@@ -187,7 +187,7 @@ public:
class sf2InstrumentView : public InstrumentView
class sf2InstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -600,7 +600,7 @@ public:
sfxrInstrumentView::sfxrInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
srand(time(NULL));
setAutoFillBackground( true );

View File

@@ -223,7 +223,7 @@ private:
class sfxrInstrumentView : public InstrumentView
class sfxrInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -483,7 +483,7 @@ public:
sidInstrumentView::sidInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );

View File

@@ -132,7 +132,7 @@ private:
class sidInstrumentView : public InstrumentView
class sidInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -384,7 +384,7 @@ PluginView * malletsInstrument::instantiateView( QWidget * _parent )
malletsInstrumentView::malletsInstrumentView( malletsInstrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
m_modalBarWidget = setupModalBarControls( this );
setWidgetBackground( m_modalBarWidget, "artwork" );

View File

@@ -187,7 +187,7 @@ private:
} ;
class malletsInstrumentView: public InstrumentView
class malletsInstrumentView: public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -419,7 +419,7 @@ public:
TripleOscillatorView::TripleOscillatorView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );
QPalette pal;

View File

@@ -136,7 +136,7 @@ private:
class TripleOscillatorView : public InstrumentView
class TripleOscillatorView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -82,11 +82,11 @@ Plugin::Descriptor Q_DECL_EXPORT vestige_plugin_descriptor =
}
class vstSubWin : public QMdiSubWindow
class vstSubWin : public SubWindow
{
public:
vstSubWin( QWidget * _parent ) :
QMdiSubWindow( _parent )
SubWindow( _parent )
{
setAttribute( Qt::WA_DeleteOnClose, false );
setWindowFlags( Qt::WindowCloseButtonHint );
@@ -468,7 +468,7 @@ PluginView * vestigeInstrument::instantiateView( QWidget * _parent )
VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent ),
InstrumentViewFixedSize( _instrument, _parent ),
lastPosInMenu (0)
{
if( s_artwork == NULL )
@@ -900,7 +900,7 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * )
manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrument,
QWidget * _parent, vestigeInstrument * m_vi2 ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
m_vi = m_vi2;
m_vi->m_scrollArea = new QScrollArea( this );

View File

@@ -29,14 +29,13 @@
#include <QMutex>
#include <QLayout>
#include <QMdiSubWindow>
#include <QScrollArea>
#include "Instrument.h"
#include "InstrumentView.h"
#include "Note.h"
#include "Knob.h"
#include "SubWindow.h"
#include "AutomatableModel.h"
@@ -98,7 +97,7 @@ private:
} ;
class manageVestigeInstrumentView : public InstrumentView
class manageVestigeInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:
@@ -134,7 +133,7 @@ private:
} ;
class VestigeInstrumentView : public InstrumentView
class VestigeInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -349,7 +349,7 @@ PluginView * vibed::instantiateView( QWidget * _parent )
vibedView::vibedView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );
QPalette pal;

View File

@@ -82,7 +82,7 @@ private:
class vibedView : public InstrumentView
class vibedView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

View File

@@ -666,7 +666,7 @@ void WatsynInstrument::updateWaveB2()
WatsynView::WatsynView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentView( _instrument, _parent )
InstrumentViewFixedSize( _instrument, _parent )
{
setAutoFillBackground( true );
QPalette pal;

View File

@@ -293,7 +293,7 @@ private:
};
class WatsynView : public InstrumentView
class WatsynView : public InstrumentViewFixedSize
{
Q_OBJECT
public:

Some files were not shown because too many files have changed in this diff Show More