Merge branch 'master' into groove
@@ -26,7 +26,7 @@
|
||||
#include "Amplifier.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "BassBooster.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "Bitcrush.h"
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
const int OS_RATE = 5;
|
||||
const float OS_RATIO = 1.0f / OS_RATE;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
SET(CMAKE_DEBUG_POSTFIX "")
|
||||
|
||||
# Enable C++11
|
||||
@@ -11,100 +11,10 @@ ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${SAMPLERATE_INCLUDE_DIRS}
|
||||
"${CMAKE_BINARY_DIR}/src"
|
||||
)
|
||||
|
||||
SET(PLUGIN_LIST "" CACHE STRING "List of plug-ins to build")
|
||||
|
||||
STRING(REPLACE " " ";" PLUGIN_LIST "${PLUGIN_LIST}")
|
||||
|
||||
OPTION(LMMS_MINIMAL "Build a minimal list of plug-ins" OFF)
|
||||
|
||||
SET(MINIMAL_LIST
|
||||
audio_file_processor
|
||||
kicker
|
||||
triple_oscillator
|
||||
)
|
||||
|
||||
IF(LMMS_MINIMAL)
|
||||
IF("${PLUGIN_LIST}" STREQUAL "")
|
||||
STRING(REPLACE ";" " " MINIMAL_LIST_STRING "${MINIMAL_LIST}")
|
||||
MESSAGE(
|
||||
"-- Using minimal plug-ins: ${MINIMAL_LIST_STRING}\n"
|
||||
" Note: You can specify specific plug-ins using -DPLUGIN_LIST=\"foo bar\""
|
||||
)
|
||||
ENDIF()
|
||||
SET(PLUGIN_LIST ${MINIMAL_LIST} ${PLUGIN_LIST})
|
||||
ENDIF()
|
||||
|
||||
IF("${PLUGIN_LIST}" STREQUAL "")
|
||||
SET(PLUGIN_LIST
|
||||
${MINIMAL_LIST}
|
||||
Amplifier
|
||||
BassBooster
|
||||
bit_invader
|
||||
Bitcrush
|
||||
carlabase
|
||||
carlapatchbay
|
||||
carlarack
|
||||
CrossoverEQ
|
||||
Delay
|
||||
DualFilter
|
||||
dynamics_processor
|
||||
Eq
|
||||
Flanger
|
||||
HydrogenImport
|
||||
ladspa_browser
|
||||
LadspaEffect
|
||||
lb302
|
||||
MidiImport
|
||||
MidiExport
|
||||
MultitapEcho
|
||||
monstro
|
||||
nes
|
||||
OpulenZ
|
||||
organic
|
||||
FreeBoy
|
||||
patman
|
||||
peak_controller_effect
|
||||
GigPlayer
|
||||
ReverbSC
|
||||
sf2_player
|
||||
sfxr
|
||||
sid
|
||||
SpectrumAnalyzer
|
||||
stereo_enhancer
|
||||
stereo_matrix
|
||||
stk
|
||||
vestige
|
||||
vst_base
|
||||
VstEffect
|
||||
watsyn
|
||||
waveshaper
|
||||
vibed
|
||||
Xpressive
|
||||
zynaddsubfx
|
||||
)
|
||||
|
||||
ENDIF("${PLUGIN_LIST}" STREQUAL "")
|
||||
|
||||
IF(MSVC)
|
||||
SET(MSVC_INCOMPATIBLE_PLUGINS
|
||||
LadspaEffect
|
||||
monstro
|
||||
organic
|
||||
ReverbSC
|
||||
sid
|
||||
vestige
|
||||
vibed
|
||||
vst_base
|
||||
VstEffect
|
||||
Xpressive
|
||||
zynaddsubfx
|
||||
)
|
||||
message(WARNING "Compiling with MSVC. The following plugins are not available: ${MSVC_INCOMPATIBLE_PLUGINS}")
|
||||
LIST(REMOVE_ITEM PLUGIN_LIST ${MSVC_INCOMPATIBLE_PLUGINS})
|
||||
ENDIF()
|
||||
|
||||
# See cmake/modules/PluginList.cmake
|
||||
FOREACH(PLUGIN ${PLUGIN_LIST})
|
||||
ADD_SUBDIRECTORY(${PLUGIN})
|
||||
ENDFOREACH()
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "CrossoverEQ.h"
|
||||
#include "lmms_math.h"
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "Engine.h"
|
||||
#include "embed.h"
|
||||
#include "interpolation.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "embed.h"
|
||||
#include "BasicFilters.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${FFTW3F_LIBRARY_DIRS})
|
||||
LINK_LIBRARIES(${FFTW3F_LIBRARIES})
|
||||
BUILD_PLUGIN(eq EqEffect.cpp EqCurve.cpp EqCurve.h EqControls.cpp EqControlsDialog.cpp EqFilter.h EqParameterWidget.cpp EqFader.h EqSpectrumView.h EqSpectrumView.cpp
|
||||
MOCFILES EqControls.h EqControlsDialog.h EqCurve.h EqParameterWidget.h EqFader.h EqSpectrumView.h EMBEDDED_RESOURCES *.png)
|
||||
|
||||
@@ -55,10 +55,10 @@ EqControlsDialog::EqControlsDialog( EqControls *controls ) :
|
||||
|
||||
EqSpectrumView * inSpec = new EqSpectrumView( &controls->m_inFftBands, this );
|
||||
inSpec->move( 26, 17 );
|
||||
inSpec->setColor( QColor( 54, 45, 142, 150 ) );
|
||||
inSpec->setColor( QColor( 77, 101, 242, 150 ) );
|
||||
|
||||
EqSpectrumView * outSpec = new EqSpectrumView( &controls->m_outFftBands, this );
|
||||
outSpec->setColor( QColor( 9, 166, 156, 150 ) );
|
||||
outSpec->setColor( QColor( 0, 255, 239, 150 ) );
|
||||
outSpec->move( 26, 17 );
|
||||
|
||||
m_parameterWidget = new EqParameterWidget( this , controls );
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
|
||||
#include "EqEffect.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "Engine.h"
|
||||
#include "EqFader.h"
|
||||
#include "interpolation.h"
|
||||
#include "lmms_math.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -80,7 +80,7 @@ private slots:
|
||||
{
|
||||
const float opl = getPeak_L();
|
||||
const float opr = getPeak_R();
|
||||
const float fall_off = 1.2;
|
||||
const float fallOff = 1.07;
|
||||
if( *m_lPeak > opl )
|
||||
{
|
||||
setPeak_L( *m_lPeak );
|
||||
@@ -88,7 +88,7 @@ private slots:
|
||||
}
|
||||
else
|
||||
{
|
||||
setPeak_L( opl/fall_off );
|
||||
setPeak_L( opl/fallOff );
|
||||
}
|
||||
|
||||
if( *m_rPeak > opr )
|
||||
@@ -98,7 +98,7 @@ private slots:
|
||||
}
|
||||
else
|
||||
{
|
||||
setPeak_R( opr/fall_off );
|
||||
setPeak_R( opr/fallOff );
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -45,11 +45,11 @@ EqAnalyser::EqAnalyser() :
|
||||
const float a2 = 0.14128;
|
||||
const float a3 = 0.01168;
|
||||
|
||||
for(int i = 0; i < FFT_BUFFER_SIZE; i++)
|
||||
for (int i = 0; i < FFT_BUFFER_SIZE; i++)
|
||||
{
|
||||
m_fftWindow[i] = ( a0 - a1 * cosf( 2 * F_PI * i / (float)FFT_BUFFER_SIZE - 1 )
|
||||
+ a2 * cosf( 4 * F_PI * i / (float)FFT_BUFFER_SIZE-1)
|
||||
- a3 * cos( 6 * F_PI * i / (float)FFT_BUFFER_SIZE - 1.0 ));
|
||||
m_fftWindow[i] = (a0 - a1 * cos(2 * F_PI * i / ((float)FFT_BUFFER_SIZE - 1.0))
|
||||
+ a2 * cos(4 * F_PI * i / ((float)FFT_BUFFER_SIZE - 1.0))
|
||||
- a3 * cos(6 * F_PI * i / ((float)FFT_BUFFER_SIZE - 1.0)));
|
||||
}
|
||||
clear();
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void EqSpectrumView::paintEvent(QPaintEvent *event)
|
||||
float peak;
|
||||
m_path.moveTo( 0, height() );
|
||||
m_peakSum = 0;
|
||||
float fallOff = 1.2;
|
||||
const float fallOff = 1.07;
|
||||
for( int x = 0; x < MAX_BANDS; ++x, ++bands )
|
||||
{
|
||||
peak = ( fh * 2.0 / 3.0 * ( 20 * ( log10( *bands / energy ) ) - LOWER_Y ) / ( - LOWER_Y ) );
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
#include "FlangerEffect.h"
|
||||
#include "Engine.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
const blip_time_t FRAME_LENGTH = 70224;
|
||||
const long CLOCK_RATE = 4194304;
|
||||
|
||||
@@ -107,11 +109,11 @@ FreeBoyInstrument::FreeBoyInstrument( InstrumentTrack * _instrument_track ) :
|
||||
m_ch1So1Model( true, this, tr( "Channel 1 to SO2 (Left)" ) ),
|
||||
m_ch2So1Model( true, this, tr( "Channel 2 to SO2 (Left)" ) ),
|
||||
m_ch3So1Model( true, this, tr( "Channel 3 to SO2 (Left)" ) ),
|
||||
m_ch4So1Model( true, this, tr( "Channel 4 to SO2 (Left)" ) ),
|
||||
m_ch4So1Model( false, this, tr( "Channel 4 to SO2 (Left)" ) ),
|
||||
m_ch1So2Model( true, this, tr( "Channel 1 to SO1 (Right)" ) ),
|
||||
m_ch2So2Model( true, this, tr( "Channel 2 to SO1 (Right)" ) ),
|
||||
m_ch3So2Model( true, this, tr( "Channel 3 to SO1 (Right)" ) ),
|
||||
m_ch4So2Model( true, this, tr( "Channel 4 to SO1 (Right)" ) ),
|
||||
m_ch4So2Model( false, this, tr( "Channel 4 to SO1 (Right)" ) ),
|
||||
m_trebleModel( -20.0f, -100.0f, 200.0f, 1.0f, this, tr( "Treble" ) ),
|
||||
m_bassModel( 461.0f, -1.0f, 600.0f, 1.0f, this, tr( "Bass" ) ),
|
||||
|
||||
@@ -281,9 +283,6 @@ void FreeBoyInstrument::playNote( NotePlayHandle * _n,
|
||||
data += m_ch4SweepStepLengthModel.value();
|
||||
papu->write_register( fakeClock(), 0xff21, data );
|
||||
|
||||
//channel 4 init
|
||||
papu->write_register( fakeClock(), 0xff23, 128 );
|
||||
|
||||
_n->m_pluginData = papu;
|
||||
}
|
||||
|
||||
@@ -385,6 +384,9 @@ void FreeBoyInstrument::playNote( NotePlayHandle * _n,
|
||||
data = data << 3;
|
||||
data += ropt;
|
||||
papu->write_register( fakeClock(), 0xff22, data );
|
||||
|
||||
//channel 4 init
|
||||
papu->write_register( fakeClock(), 0xff23, 128 );
|
||||
}
|
||||
|
||||
int const buf_size = 2048;
|
||||
@@ -455,7 +457,7 @@ public:
|
||||
|
||||
FreeBoyInstrumentView::FreeBoyInstrumentView( Instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
InstrumentView( _instrument, _parent )
|
||||
InstrumentViewFixedSize( _instrument, _parent )
|
||||
{
|
||||
|
||||
setAutoFillBackground( true );
|
||||
@@ -726,10 +728,10 @@ extern "C"
|
||||
{
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *, void * _data )
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
|
||||
{
|
||||
return( new FreeBoyInstrument(
|
||||
static_cast<InstrumentTrack *>( _data ) ) );
|
||||
static_cast<InstrumentTrack *>( m ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
} ;
|
||||
|
||||
|
||||
class FreeBoyInstrumentView : public InstrumentView
|
||||
class FreeBoyInstrumentView : public InstrumentViewFixedSize
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#include "LcdSpinBox.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -922,7 +922,7 @@ public:
|
||||
|
||||
|
||||
GigInstrumentView::GigInstrumentView( Instrument * _instrument, QWidget * _parent ) :
|
||||
InstrumentView( _instrument, _parent )
|
||||
InstrumentViewFixedSize( _instrument, _parent )
|
||||
{
|
||||
GigInstrument * k = castModel<GigInstrument>();
|
||||
|
||||
@@ -1390,9 +1390,9 @@ extern "C"
|
||||
{
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
|
||||
{
|
||||
return new GigInstrument( static_cast<InstrumentTrack *>( _data ) );
|
||||
return new GigInstrument( static_cast<InstrumentTrack *>( m ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ signals:
|
||||
|
||||
|
||||
|
||||
class GigInstrumentView : public InstrumentView
|
||||
class GigInstrumentView : public InstrumentViewFixedSize
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -74,11 +74,7 @@ PatchesDialog::PatchesDialog( QWidget * pParent, Qt::WindowFlags wflags )
|
||||
// Soundfonts list view...
|
||||
QHeaderView * pHeader = m_progListView->header();
|
||||
pHeader->setDefaultAlignment( Qt::AlignLeft );
|
||||
#if QT_VERSION >= 0x050000
|
||||
pHeader->setSectionsMovable( false );
|
||||
#else
|
||||
pHeader->setMovable( false );
|
||||
#endif
|
||||
pHeader->setStretchLastSection( true );
|
||||
|
||||
m_progListView->resizeColumnToContents( 0 ); // Prog.
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "BBTrackContainer.h"
|
||||
#include "Instrument.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
#define MAX_LAYERS 4
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -36,7 +36,8 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) :
|
||||
{
|
||||
|
||||
connect( &m_stereoLinkModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateLinkStatesFromGlobal() ) );
|
||||
this, SLOT( updateLinkStatesFromGlobal() ),
|
||||
Qt::DirectConnection );
|
||||
|
||||
multi_proc_t controls = m_effect->getPortControls();
|
||||
m_controlCount = controls.count();
|
||||
@@ -59,7 +60,8 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) :
|
||||
if( linked_control )
|
||||
{
|
||||
connect( (*it)->control, SIGNAL( linkChanged( int, bool ) ),
|
||||
this, SLOT( linkPort( int, bool ) ) );
|
||||
this, SLOT( linkPort( int, bool ) ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,6 +155,9 @@ void LadspaControls::linkPort( int _port, bool _state )
|
||||
{
|
||||
first->unlinkControls( m_controls[proc][_port] );
|
||||
}
|
||||
|
||||
// m_stereoLinkModel.setValue() will call updateLinkStatesFromGlobal()
|
||||
// m_noLink will make sure that this will not unlink any other ports
|
||||
m_noLink = true;
|
||||
m_stereoLinkModel.setValue( false );
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -122,9 +123,6 @@ void LadspaEffect::changeSampleRate()
|
||||
// the IDs of re-created controls have been saved and now need to be
|
||||
// resolved again
|
||||
AutomationPattern::resolveAllIDs();
|
||||
|
||||
// make sure, connections are ok
|
||||
ControllerConnection::finalizeConnections();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,16 @@ LadspaSubPluginFeatures::LadspaSubPluginFeatures( Plugin::PluginTypes _type ) :
|
||||
|
||||
|
||||
|
||||
QString LadspaSubPluginFeatures::displayName(const Plugin::Descriptor::SubPluginFeatures::Key &k) const
|
||||
{
|
||||
const ladspa_key_t & lkey = subPluginKeyToLadspaKey(&k);
|
||||
Ladspa2LMMS * lm = Engine::getLADSPAManager();
|
||||
return lm->getName(lkey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaSubPluginFeatures::fillDescriptionWidget( QWidget * _parent,
|
||||
const Key * _key ) const
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LADSPA_SUBPLUGIN_FEATURES_H
|
||||
#define _LADSPA_SUBPLUGIN_FEATURES_H
|
||||
#ifndef LADSPA_SUBPLUGIN_FEATURES_H
|
||||
#define LADSPA_SUBPLUGIN_FEATURES_H
|
||||
|
||||
#include "LadspaManager.h"
|
||||
#include "Plugin.h"
|
||||
@@ -37,11 +37,13 @@ class LadspaSubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures
|
||||
public:
|
||||
LadspaSubPluginFeatures( Plugin::PluginTypes _type );
|
||||
|
||||
virtual void fillDescriptionWidget( QWidget * _parent,
|
||||
const Key * _key ) const;
|
||||
QString displayName(const Key& k) const override;
|
||||
void fillDescriptionWidget( QWidget * _parent,
|
||||
const Key * _key ) const override;
|
||||
|
||||
virtual void listSubPluginKeys( const Plugin::Descriptor * _desc,
|
||||
KeyList & _kl ) const;
|
||||
KeyList & _kl ) const override;
|
||||
|
||||
|
||||
static ladspa_key_t subPluginKeyToLadspaKey( const Key * _key );
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@ LIST(SORT SOURCES)
|
||||
# Skip files matching pattern
|
||||
SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win;plugin.cpp")
|
||||
FOREACH(_item ${SOURCES})
|
||||
GET_FILENAME_COMPONENT(m_basename ${_item} NAME)
|
||||
FOREACH(_pattern ${FILE_PATTERNS})
|
||||
IF(${_item} MATCHES ${_pattern})
|
||||
IF(${m_basename} MATCHES ${_pattern})
|
||||
LIST(REMOVE_ITEM SOURCES ${_item})
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
|
||||
@@ -8,13 +8,6 @@ ELSE()
|
||||
SET(PIC_FLAGS "-fPIC -DPIC")
|
||||
ENDIF()
|
||||
|
||||
# Additional link flags
|
||||
IF(LMMS_BUILD_WIN32 AND MINGW_PREFIX)
|
||||
SET(LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined -Wl,-Bsymbolic -lm")
|
||||
ELSEIF(LMMS_BUILD_APPLE)
|
||||
SET(LINK_FLAGS "${LINK_FLAGS} -Bsymbolic -lm")
|
||||
ENDIF()
|
||||
|
||||
# Additional compile flags
|
||||
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -O3 -Wall")
|
||||
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -funroll-loops -ffast-math -c -fno-strict-aliasing")
|
||||
@@ -42,7 +35,10 @@ FOREACH(_item ${XML_SOURCES})
|
||||
|
||||
# Vocoder does not use fftw
|
||||
IF(NOT ("${_plugin}" STREQUAL "vocoder_1337"))
|
||||
TARGET_LINK_LIBRARIES("${_plugin}" -lfftw3f)
|
||||
TARGET_LINK_LIBRARIES("${_plugin}" ${FFTW3F_LIBRARIES})
|
||||
ENDIF()
|
||||
IF(NOT MSVC)
|
||||
TARGET_LINK_LIBRARIES("${_plugin}" m)
|
||||
ENDIF()
|
||||
|
||||
SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES PREFIX "")
|
||||
@@ -55,10 +51,9 @@ ADD_DEFINITIONS(-DFFTW3)
|
||||
INCLUDE_DIRECTORIES(
|
||||
"${CMAKE_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/ladspa"
|
||||
${FFTW3F_INCLUDE_DIRS}
|
||||
"${FFTW3F_INCLUDE_DIRS}"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
LINK_DIRECTORIES(${FFTW3F_LIBRARY_DIRS})
|
||||
|
||||
ADD_LIBRARY(iir STATIC ladspa/util/iir.c)
|
||||
SET_TARGET_PROPERTIES(iir PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
|
||||
|
||||
@@ -15,13 +15,8 @@ FOREACH(_item ${PLUGIN_SOURCES})
|
||||
IF(LMMS_BUILD_WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES "Deb")
|
||||
ADD_CUSTOM_COMMAND(TARGET "${_plugin}" POST_BUILD COMMAND "${STRIP}" \"$<TARGET_FILE:${_plugin}>\")
|
||||
ENDIF()
|
||||
IF(LMMS_BUILD_APPLE)
|
||||
SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Bsymbolic -lm")
|
||||
ELSEIF(NOT LMMS_BUILD_OPENBSD)
|
||||
SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined -Wl,-Bsymbolic -lm")
|
||||
ENDIF()
|
||||
IF(LMMS_BUILD_LINUX OR LMMS_BUILD_HAIKU)
|
||||
SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES LINK_FLAGS "${LINK_FLAGS}")
|
||||
IF(NOT MSVC)
|
||||
TARGET_LINK_LIBRARIES("${_plugin}" m)
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
#include "TrackContainer.h"
|
||||
#include "BBTrack.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "LocaleHelper.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -133,7 +135,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks,
|
||||
{
|
||||
base_pitch += masterPitch;
|
||||
}
|
||||
base_volume = it.attribute("volume", "100").toDouble()/100.0;
|
||||
base_volume = LocaleHelper::toDouble(it.attribute("volume", "100"))/100.0;
|
||||
}
|
||||
|
||||
if (n.nodeName() == "pattern")
|
||||
@@ -204,7 +206,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks,
|
||||
{
|
||||
base_pitch += masterPitch;
|
||||
}
|
||||
base_volume = it.attribute("volume", "100").toDouble() / 100.0;
|
||||
base_volume = LocaleHelper::toDouble(it.attribute("volume", "100")) / 100.0;
|
||||
}
|
||||
|
||||
if (n.nodeName() == "pattern")
|
||||
@@ -273,7 +275,8 @@ void MidiExport::writePattern(MidiNoteVector &pat, QDomNode n,
|
||||
// TODO interpret pan="0" fxch="0" pitchrange="1"
|
||||
MidiNote mnote;
|
||||
mnote.pitch = qMax(0, qMin(127, note.attribute("key", "0").toInt() + base_pitch));
|
||||
mnote.volume = qMin(qRound(base_volume * note.attribute("vol", "100").toDouble()), 127);
|
||||
// Map from LMMS volume to MIDI velocity
|
||||
mnote.volume = qMin(qRound(base_volume * LocaleHelper::toDouble(note.attribute("vol", "100")) * (127.0 / 200.0)), 127);
|
||||
mnote.time = base_time + note.attribute("pos", "0").toInt();
|
||||
mnote.duration = note.attribute("len", "0").toInt();
|
||||
pat.push_back(mnote);
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
#include <QDomDocument>
|
||||
#include <QDir>
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "MidiImport.h"
|
||||
#include "TrackContainer.h"
|
||||
#include "InstrumentTrack.h"
|
||||
@@ -41,9 +44,11 @@
|
||||
#include "MainWindow.h"
|
||||
#include "MidiTime.h"
|
||||
#include "debug.h"
|
||||
#include "embed.h"
|
||||
#include "Song.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
#include "portsmf/allegro.h"
|
||||
|
||||
#define makeID(_c0, _c1, _c2, _c3) \
|
||||
@@ -98,11 +103,11 @@ bool MidiImport::tryImport( TrackContainer* tc )
|
||||
|
||||
#ifdef LMMS_HAVE_FLUIDSYNTH
|
||||
if( gui != NULL &&
|
||||
ConfigManager::inst()->defaultSoundfont().isEmpty() )
|
||||
ConfigManager::inst()->sf2File().isEmpty() )
|
||||
{
|
||||
QMessageBox::information( gui->mainWindow(),
|
||||
tr( "Setup incomplete" ),
|
||||
tr( "You do not have set up a default soundfont in "
|
||||
tr( "You have not set up a default soundfont in "
|
||||
"the settings dialog (Edit->Settings). "
|
||||
"Therefore no sound will be played back after "
|
||||
"importing this MIDI file. You should download "
|
||||
@@ -183,9 +188,9 @@ public:
|
||||
|
||||
smfMidiCC & putValue( MidiTime time, AutomatableModel * objModel, float value )
|
||||
{
|
||||
if( !ap || time > lastPos + DefaultTicksPerTact )
|
||||
if( !ap || time > lastPos + DefaultTicksPerBar )
|
||||
{
|
||||
MidiTime pPos = MidiTime( time.getTact(), 0 );
|
||||
MidiTime pPos = MidiTime( time.getBar(), 0 );
|
||||
ap = dynamic_cast<AutomationPattern*>(
|
||||
at->createTCO(0) );
|
||||
ap->movePosition( pPos );
|
||||
@@ -195,7 +200,7 @@ public:
|
||||
lastPos = time;
|
||||
time = time - ap->startPosition();
|
||||
ap->putValue( time, value, false );
|
||||
ap->changeLength( MidiTime( time.getTact() + 1, 0 ) );
|
||||
ap->changeLength( MidiTime( time.getBar() + 1, 0 ) );
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -237,7 +242,7 @@ public:
|
||||
if( it_inst )
|
||||
{
|
||||
isSF2 = true;
|
||||
it_inst->loadFile( ConfigManager::inst()->defaultSoundfont() );
|
||||
it_inst->loadFile( ConfigManager::inst()->sf2File() );
|
||||
it_inst->childModel( "bank" )->setValue( 0 );
|
||||
it_inst->childModel( "patch" )->setValue( 0 );
|
||||
}
|
||||
@@ -262,9 +267,9 @@ public:
|
||||
|
||||
void addNote( Note & n )
|
||||
{
|
||||
if( !p || n.pos() > lastEnd + DefaultTicksPerTact )
|
||||
if( !p || n.pos() > lastEnd + DefaultTicksPerBar )
|
||||
{
|
||||
MidiTime pPos = MidiTime( n.pos().getTact(), 0 );
|
||||
MidiTime pPos = MidiTime( n.pos().getBar(), 0 );
|
||||
p = dynamic_cast<Pattern*>( it->createTCO( 0 ) );
|
||||
p->movePosition( pPos );
|
||||
}
|
||||
@@ -279,8 +284,6 @@ public:
|
||||
|
||||
bool MidiImport::readSMF( TrackContainer* tc )
|
||||
{
|
||||
QString filename = file().fileName();
|
||||
closeFile();
|
||||
|
||||
const int preTrackSteps = 2;
|
||||
QProgressDialog pd( TrackContainer::tr( "Importing MIDI-file..." ),
|
||||
@@ -291,7 +294,11 @@ bool MidiImport::readSMF( TrackContainer* tc )
|
||||
|
||||
pd.setValue( 0 );
|
||||
|
||||
Alg_seq_ptr seq = new Alg_seq(filename.toLocal8Bit(), true);
|
||||
std::stringstream stream;
|
||||
QByteArray arr = readAllData();
|
||||
stream.str(std::string(arr.constData(), arr.size()));
|
||||
|
||||
Alg_seq_ptr seq = new Alg_seq(stream, true);
|
||||
seq->convert_to_beats();
|
||||
|
||||
pd.setMaximum( seq->tracks() + preTrackSteps );
|
||||
@@ -302,33 +309,36 @@ bool MidiImport::readSMF( TrackContainer* tc )
|
||||
smfMidiChannel chs[256];
|
||||
|
||||
MeterModel & timeSigMM = Engine::getSong()->getTimeSigModel();
|
||||
AutomationPattern * timeSigNumeratorPat =
|
||||
AutomationPattern::globalAutomationPattern( &timeSigMM.numeratorModel() );
|
||||
AutomationPattern * timeSigDenominatorPat =
|
||||
AutomationPattern::globalAutomationPattern( &timeSigMM.denominatorModel() );
|
||||
AutomationTrack * nt = dynamic_cast<AutomationTrack*>(
|
||||
Track::create(Track::AutomationTrack, Engine::getSong()));
|
||||
nt->setName(tr("MIDI Time Signature Numerator"));
|
||||
AutomationTrack * dt = dynamic_cast<AutomationTrack*>(
|
||||
Track::create(Track::AutomationTrack, Engine::getSong()));
|
||||
dt->setName(tr("MIDI Time Signature Denominator"));
|
||||
AutomationPattern * timeSigNumeratorPat =
|
||||
new AutomationPattern(nt);
|
||||
timeSigNumeratorPat->setDisplayName(tr("Numerator"));
|
||||
timeSigNumeratorPat->addObject(&timeSigMM.numeratorModel());
|
||||
AutomationPattern * timeSigDenominatorPat =
|
||||
new AutomationPattern(dt);
|
||||
timeSigDenominatorPat->setDisplayName(tr("Denominator"));
|
||||
timeSigDenominatorPat->addObject(&timeSigMM.denominatorModel());
|
||||
|
||||
// TODO: adjust these to Time.Sig changes
|
||||
double beatsPerTact = 4;
|
||||
double ticksPerBeat = DefaultTicksPerTact / beatsPerTact;
|
||||
double beatsPerBar = 4;
|
||||
double ticksPerBeat = DefaultTicksPerBar / beatsPerBar;
|
||||
|
||||
// Time-sig changes
|
||||
Alg_time_sigs * timeSigs = &seq->time_sig;
|
||||
for( int s = 0; s < timeSigs->length(); ++s )
|
||||
{
|
||||
Alg_time_sig timeSig = (*timeSigs)[s];
|
||||
// Initial timeSig, set song-default value
|
||||
if(/* timeSig.beat == 0*/ true )
|
||||
{
|
||||
// TODO set song-global default value
|
||||
printf("Another timesig at %f\n", timeSig.beat);
|
||||
timeSigNumeratorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.num );
|
||||
timeSigDenominatorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.den );
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
timeSigNumeratorPat->putValue(timeSig.beat * ticksPerBeat, timeSig.num);
|
||||
timeSigDenominatorPat->putValue(timeSig.beat * ticksPerBeat, timeSig.den);
|
||||
}
|
||||
// manually call otherwise the pattern shows being 1 bar
|
||||
timeSigNumeratorPat->updateLength();
|
||||
timeSigDenominatorPat->updateLength();
|
||||
|
||||
pd.setValue( 2 );
|
||||
|
||||
@@ -421,7 +431,7 @@ bool MidiImport::readSMF( TrackContainer* tc )
|
||||
Note n( (ticks < 1 ? 1 : ticks ),
|
||||
noteEvt->get_start_time() * ticksPerBeat,
|
||||
noteEvt->get_identifier() - 12,
|
||||
noteEvt->get_loud());
|
||||
noteEvt->get_loud() * (200.f / 127.f)); // Map from MIDI velocity to LMMS volume
|
||||
ch->addNote( n );
|
||||
|
||||
}
|
||||
|
||||
@@ -54,8 +54,10 @@ void Alg_atoms::expand()
|
||||
maxlen += (maxlen >> 2); // add 25%
|
||||
char **new_atoms = new Alg_attribute[maxlen];
|
||||
// now do copy
|
||||
memcpy(new_atoms, atoms, len * sizeof(Alg_attribute));
|
||||
if (atoms) delete[] atoms;
|
||||
if (atoms) {
|
||||
memcpy(new_atoms, atoms, len * sizeof(Alg_attribute));
|
||||
delete[] atoms;
|
||||
}
|
||||
atoms = new_atoms;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "MultitapEcho.h"
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
#include "PixmapButton.h"
|
||||
#include "ToolTip.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -77,9 +79,9 @@ Plugin::Descriptor PLUGIN_EXPORT opulenz_plugin_descriptor =
|
||||
};
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *, void * _data )
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
|
||||
{
|
||||
return( new OpulenzInstrument( static_cast<InstrumentTrack *>( _data ) ) );
|
||||
return( new OpulenzInstrument( static_cast<InstrumentTrack *>( m ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -679,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) \
|
||||
|
||||
@@ -142,7 +142,7 @@ private:
|
||||
|
||||
|
||||
|
||||
class OpulenzInstrumentView : public InstrumentView
|
||||
class OpulenzInstrumentView : public InstrumentViewFixedSize
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ReverbSC.cpp - A native reverb based on an algorithm by Sean Costello
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "ReverbSC.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
#define DB2LIN(X) pow(10, X / 20.0f);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2017 Paul Batchelor
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2017 Paul Batchelor
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2017 Paul Batchelor
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2017 Paul Batchelor
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2017 Paul Batchelor
|
||||
*
|
||||
* This file is part of LMMS - http://lmms.io
|
||||
* 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
|
||||
|
||||
@@ -72,7 +72,7 @@ int sp_revsc_init(sp_data *sp, sp_revsc *p)
|
||||
sp_auxdata_alloc(&p->aux, nBytes);
|
||||
nBytes = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
p->delayLines[i].buf = (p->aux.ptr) + nBytes;
|
||||
p->delayLines[i].buf = (SPFLOAT*) (((char*) p->aux.ptr) + nBytes);
|
||||
init_delay_line(p, &p->delayLines[i], i);
|
||||
nBytes += delay_line_bytes_alloc(sp->sr, 1, i);
|
||||
}
|
||||
|
||||
75
plugins/SpectrumAnalyzer/Analyzer.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${FFTW3F_LIBRARY_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)
|
||||
|
||||
19
plugins/SpectrumAnalyzer/README.md
Normal 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
|
||||
144
plugins/SpectrumAnalyzer/SaControls.cpp
Normal 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");
|
||||
}
|
||||
126
plugins/SpectrumAnalyzer/SaControls.h
Normal 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
|
||||
227
plugins/SpectrumAnalyzer/SaControlsDialog.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
57
plugins/SpectrumAnalyzer/SaControlsDialog.h
Normal 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
|
||||
571
plugins/SpectrumAnalyzer/SaProcessor.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
122
plugins/SpectrumAnalyzer/SaProcessor.h
Normal 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
|
||||
|
||||
796
plugins/SpectrumAnalyzer/SaSpectrumView.cpp
Normal 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());
|
||||
}
|
||||
|
||||
126
plugins/SpectrumAnalyzer/SaSpectrumView.h
Normal 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
|
||||
|
||||
230
plugins/SpectrumAnalyzer/SaWaterfallView.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
|
||||
66
plugins/SpectrumAnalyzer/SaWaterfallView.h
Normal 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
|
||||
@@ -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"
|
||||
|
||||
|
||||
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 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 859 B |
273
plugins/SpectrumAnalyzer/block_size.svg
Normal 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 |
296
plugins/SpectrumAnalyzer/freeze.svg
Normal 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 |
297
plugins/SpectrumAnalyzer/freeze_off.svg
Normal 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 |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 734 B |
220
plugins/SpectrumAnalyzer/pause.svg
Normal 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 |
219
plugins/SpectrumAnalyzer/play.svg
Normal 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 |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 819 B |
232
plugins/SpectrumAnalyzer/window.svg
Normal 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 |
242
plugins/SpectrumAnalyzer/x_linear.svg
Normal 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 |
240
plugins/SpectrumAnalyzer/x_log.svg
Normal 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 |
240
plugins/SpectrumAnalyzer/y_linear.svg
Normal 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 |
240
plugins/SpectrumAnalyzer/y_log.svg
Normal 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 |
@@ -11,9 +11,7 @@ ELSE()
|
||||
ENDIF()
|
||||
|
||||
BUILD_PLUGIN(vsteffect VstEffect.cpp VstEffectControls.cpp VstEffectControlDialog.cpp VstSubPluginFeatures.cpp VstEffect.h VstEffectControls.h VstEffectControlDialog.h VstSubPluginFeatures.h MOCFILES VstEffectControlDialog.h VstEffectControls.h EMBEDDED_RESOURCES *.png)
|
||||
SET_TARGET_PROPERTIES(vsteffect PROPERTIES COMPILE_FLAGS "-Wno-attributes")
|
||||
TARGET_LINK_LIBRARIES(vsteffect -lvstbase)
|
||||
ADD_DEPENDENCIES(vsteffect vstbase)
|
||||
TARGET_LINK_LIBRARIES(vsteffect vstbase)
|
||||
|
||||
ENDIF(LMMS_SUPPORT_VST)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "VstSubPluginFeatures.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -95,9 +95,11 @@ bool VstEffect::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames )
|
||||
sampleFrame * buf = new sampleFrame[_frames];
|
||||
#endif
|
||||
memcpy( buf, _buf, sizeof( sampleFrame ) * _frames );
|
||||
m_pluginMutex.lock();
|
||||
m_plugin->process( buf, buf );
|
||||
m_pluginMutex.unlock();
|
||||
if (m_pluginMutex.tryLock(Engine::getSong()->isExporting() ? -1 : 0))
|
||||
{
|
||||
m_plugin->process( buf, buf );
|
||||
m_pluginMutex.unlock();
|
||||
}
|
||||
|
||||
double out_sum = 0.0;
|
||||
const float w = wetLevel();
|
||||
@@ -143,9 +145,6 @@ void VstEffect::openPlugin( const QString & _plugin )
|
||||
return;
|
||||
}
|
||||
|
||||
VstPlugin::connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), m_plugin.data(), SLOT( setTempo( bpm_t ) ) );
|
||||
m_plugin->setTempo( Engine::getSong()->getTempo() );
|
||||
|
||||
delete tf;
|
||||
|
||||
m_key.attributes["file"] = _plugin;
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
#include <QToolBar>
|
||||
#include <QLabel>
|
||||
|
||||
|
||||
VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
EffectControlDialog( _ctl ),
|
||||
m_pluginWidget( NULL ),
|
||||
|
||||
m_plugin( NULL ),
|
||||
tbLabel( NULL )
|
||||
{
|
||||
@@ -62,24 +62,18 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
embed_vst = m_plugin->embedMethod() != "none";
|
||||
|
||||
if (embed_vst) {
|
||||
m_plugin->createUI( nullptr, true );
|
||||
m_pluginWidget = m_plugin->pluginWidget( false );
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
if( !m_pluginWidget )
|
||||
{
|
||||
m_pluginWidget = m_plugin->pluginWidget( false );
|
||||
if (m_plugin->hasEditor() && ! m_plugin->pluginWidget()) {
|
||||
m_plugin->createUI(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_pluginWidget = m_plugin->pluginWidget();
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_plugin && (!embed_vst || m_pluginWidget) )
|
||||
if (m_plugin)
|
||||
{
|
||||
setWindowTitle( m_plugin->name() );
|
||||
|
||||
QPushButton * btn = new QPushButton( tr( "Show/hide" ) );
|
||||
QPushButton * btn = new QPushButton( tr( "Show/hide" ));
|
||||
|
||||
if (embed_vst) {
|
||||
btn->setCheckable( true );
|
||||
@@ -87,14 +81,15 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
connect( btn, SIGNAL( toggled( bool ) ),
|
||||
SLOT( togglePluginUI( bool ) ) );
|
||||
} else {
|
||||
connect( btn, SIGNAL( clicked( bool ) ),
|
||||
SLOT( togglePluginUI( bool ) ) );
|
||||
connect( btn, SIGNAL( clicked() ),
|
||||
m_plugin.data(), SLOT( toggleUI() ) );
|
||||
}
|
||||
|
||||
btn->setMinimumWidth( 78 );
|
||||
btn->setMaximumWidth( 78 );
|
||||
btn->setMinimumHeight( 24 );
|
||||
btn->setMaximumHeight( 24 );
|
||||
m_togglePluginButton = btn;
|
||||
|
||||
m_managePluginButton = new PixmapButton( this, "" );
|
||||
m_managePluginButton->setCheckable( false );
|
||||
@@ -206,7 +201,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
|
||||
int newSize = 0;
|
||||
|
||||
if (embed_vst) {
|
||||
if (m_pluginWidget) {
|
||||
newSize = m_pluginWidget->width() + 20;
|
||||
}
|
||||
newSize = std::max(newSize, 250);
|
||||
@@ -222,7 +217,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
l->addItem( new QSpacerItem( newSize - 20, 30, QSizePolicy::Fixed,
|
||||
QSizePolicy::Fixed ), 1, 0 );
|
||||
l->addWidget( resize, 2, 0, 1, 1, Qt::AlignCenter );
|
||||
if (embed_vst) {
|
||||
if (m_pluginWidget) {
|
||||
l->addWidget( m_pluginWidget, 3, 0, 1, 1, Qt::AlignCenter );
|
||||
}
|
||||
l->setRowStretch( 5, 1 );
|
||||
@@ -261,12 +256,26 @@ void VstEffectControlDialog::paintEvent( QPaintEvent * )
|
||||
}
|
||||
}
|
||||
|
||||
void VstEffectControlDialog::showEvent(QShowEvent *_se)
|
||||
{
|
||||
EffectControlDialog::showEvent( _se );
|
||||
// Workaround for a (unexplained) bug where on project-load the effect
|
||||
// control window has size 0 and would only restore to the proper size upon
|
||||
// moving the window or interacting with it.
|
||||
if (parentWidget()) {
|
||||
parentWidget()->adjustSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
VstEffectControlDialog::~VstEffectControlDialog()
|
||||
{
|
||||
//delete m_pluginWidget;
|
||||
if (m_pluginWidget && layout()) {
|
||||
layout()->removeWidget(m_pluginWidget);
|
||||
m_pluginWidget->setParent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +287,14 @@ void VstEffectControlDialog::togglePluginUI( bool checked )
|
||||
return;
|
||||
}
|
||||
|
||||
m_plugin->toggleUI();
|
||||
if ( m_togglePluginButton->isChecked() != checked ) {
|
||||
m_togglePluginButton->setChecked( checked );
|
||||
}
|
||||
|
||||
if ( checked ) {
|
||||
m_plugin->showUI();
|
||||
} else {
|
||||
m_plugin->hideUI();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,11 +49,13 @@ public:
|
||||
virtual ~VstEffectControlDialog();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
void paintEvent( QPaintEvent * _pe ) override;
|
||||
void showEvent( QShowEvent* _se ) override;
|
||||
|
||||
private:
|
||||
QWidget * m_pluginWidget;
|
||||
|
||||
QPushButton * m_togglePluginButton;
|
||||
PixmapButton * m_openPresetButton;
|
||||
PixmapButton * m_rolLPresetButton;
|
||||
PixmapButton * m_rolRPresetButton;
|
||||
@@ -64,7 +66,7 @@ private:
|
||||
|
||||
QLabel * tbLabel;
|
||||
|
||||
private slots:
|
||||
public slots:
|
||||
void togglePluginUI( bool checked );
|
||||
} ;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "VstEffectControls.h"
|
||||
#include "VstEffect.h"
|
||||
|
||||
#include "LocaleHelper.h"
|
||||
#include "MainWindow.h"
|
||||
#include "GuiApplication.h"
|
||||
#include <QMdiArea>
|
||||
@@ -40,7 +41,8 @@ VstEffectControls::VstEffectControls( VstEffect * _eff ) :
|
||||
m_subWindow( NULL ),
|
||||
knobFModel( NULL ),
|
||||
ctrHandle( NULL ),
|
||||
lastPosInMenu (0)
|
||||
lastPosInMenu (0),
|
||||
m_vstGuiVisible ( true )
|
||||
// m_presetLabel ( NULL )
|
||||
{
|
||||
}
|
||||
@@ -64,6 +66,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this )
|
||||
m_effect->m_pluginMutex.lock();
|
||||
if( m_effect->m_plugin != NULL )
|
||||
{
|
||||
m_vstGuiVisible = _this.attribute( "guivisible" ).toInt();
|
||||
|
||||
m_effect->m_plugin->loadSettings( _this );
|
||||
|
||||
const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
|
||||
@@ -82,11 +86,12 @@ void VstEffectControls::loadSettings( const QDomElement & _this )
|
||||
if( !( knobFModel[ i ]->isAutomated() ||
|
||||
knobFModel[ i ]->controllerConnection() ) )
|
||||
{
|
||||
knobFModel[ i ]->setValue( (s_dumpValues.at( 2 ) ).toFloat() );
|
||||
knobFModel[ i ]->setInitValue( (s_dumpValues.at( 2 ) ).toFloat() );
|
||||
knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
|
||||
knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
|
||||
}
|
||||
|
||||
connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) );
|
||||
connect( knobFModel[i], &FloatModel::dataChanged, this,
|
||||
[this, i]() { setParameter( knobFModel[i] ); }, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -96,10 +101,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this )
|
||||
|
||||
|
||||
|
||||
void VstEffectControls::setParameter( void )
|
||||
void VstEffectControls::setParameter( Model * action )
|
||||
{
|
||||
|
||||
Model *action = qobject_cast<Model *>(sender());
|
||||
int knobUNID = action->displayName().toInt();
|
||||
|
||||
if ( m_effect->m_plugin != NULL ) {
|
||||
@@ -138,8 +141,16 @@ void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
|
||||
int VstEffectControls::controlCount()
|
||||
{
|
||||
return m_effect->m_plugin != NULL &&
|
||||
m_effect->m_plugin->hasEditor() ? 1 : 0;
|
||||
return m_effect->m_plugin != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EffectControlDialog *VstEffectControls::createView()
|
||||
{
|
||||
auto dialog = new VstEffectControlDialog( this );
|
||||
dialog->togglePluginUI( m_vstGuiVisible );
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,18 +209,16 @@ void VstEffectControls::updateMenu( void )
|
||||
QMenu * to_menu = m_selPresetButton->menu();
|
||||
to_menu->clear();
|
||||
|
||||
QAction *presetActions[list1.size()];
|
||||
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
presetActions[i] = new QAction(this);
|
||||
connect(presetActions[i], SIGNAL(triggered()), this, SLOT(selPreset()));
|
||||
QAction* presetAction = new QAction(this);
|
||||
connect(presetAction, SIGNAL(triggered()), this, SLOT(selPreset()));
|
||||
|
||||
presetActions[i]->setText(QString("%1. %2").arg(QString::number(i+1), list1.at(i)));
|
||||
presetActions[i]->setData(i);
|
||||
presetAction->setText(QString("%1. %2").arg(QString::number(i+1), list1.at(i)));
|
||||
presetAction->setData(i);
|
||||
if (i == lastPosInMenu) {
|
||||
presetActions[i]->setIcon(embed::getIconPixmap( "sample_file", 16, 16 ));
|
||||
} else presetActions[i]->setIcon(embed::getIconPixmap( "edit_copy", 16, 16 ));
|
||||
to_menu->addAction( presetActions[i] );
|
||||
presetAction->setIcon(embed::getIconPixmap( "sample_file", 16, 16 ));
|
||||
} else presetAction->setIcon(embed::getIconPixmap( "edit_copy", 16, 16 ));
|
||||
to_menu->addAction( presetAction );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -306,7 +315,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls *
|
||||
m_vi->m_subWindow->setWidget(m_vi->m_scrollArea);
|
||||
m_vi->m_subWindow->setWindowTitle( _eff->m_plugin->name() + tr( " - VST parameter control" ) );
|
||||
m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) );
|
||||
//m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
|
||||
|
||||
l->setContentsMargins( 20, 10, 10, 10 );
|
||||
@@ -364,12 +373,14 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls *
|
||||
if( !hasKnobModel )
|
||||
{
|
||||
sprintf( paramStr, "%d", i);
|
||||
m_vi->knobFModel[ i ] = new FloatModel( ( s_dumpValues.at( 2 ) ).toFloat(),
|
||||
m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)),
|
||||
0.0f, 1.0f, 0.01f, _eff, tr( paramStr ) );
|
||||
}
|
||||
connect( m_vi->knobFModel[ i ], SIGNAL( dataChanged() ), this,
|
||||
SLOT( setParameter() ) );
|
||||
vstKnobs[ i ] ->setModel( m_vi->knobFModel[ i ] );
|
||||
|
||||
FloatModel * model = m_vi->knobFModel[i];
|
||||
connect( model, &FloatModel::dataChanged, this,
|
||||
[this, model]() { setParameter( model ); }, Qt::DirectConnection);
|
||||
vstKnobs[ i ] ->setModel( model );
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -428,7 +439,7 @@ void manageVSTEffectView::syncPlugin( void )
|
||||
{
|
||||
sprintf( paramStr, "param%d", i );
|
||||
s_dumpValues = dump[ paramStr ].split( ":" );
|
||||
f_value = ( s_dumpValues.at( 2 ) ).toFloat();
|
||||
f_value = LocaleHelper::toFloat(s_dumpValues.at(2));
|
||||
m_vi2->knobFModel[ i ]->setAutomatedValue( f_value );
|
||||
m_vi2->knobFModel[ i ]->setInitValue( f_value );
|
||||
}
|
||||
@@ -462,10 +473,8 @@ void manageVSTEffectView::displayAutomatedOnly( void )
|
||||
|
||||
|
||||
|
||||
void manageVSTEffectView::setParameter( void )
|
||||
void manageVSTEffectView::setParameter( Model * action )
|
||||
{
|
||||
|
||||
Model *action = qobject_cast<Model *>(sender());
|
||||
int knobUNID = action->displayName().toInt();
|
||||
|
||||
if ( m_effect->m_plugin != NULL ) {
|
||||
|
||||
@@ -59,10 +59,7 @@ public:
|
||||
|
||||
virtual int controlCount();
|
||||
|
||||
virtual EffectControlDialog * createView()
|
||||
{
|
||||
return new VstEffectControlDialog( this );
|
||||
}
|
||||
virtual EffectControlDialog * createView();
|
||||
|
||||
|
||||
protected slots:
|
||||
@@ -73,7 +70,7 @@ protected slots:
|
||||
void rollPreset( void );
|
||||
void rolrPreset( void );
|
||||
void selPreset( void );
|
||||
void setParameter( void );
|
||||
void setParameter( Model * action );
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
@@ -96,6 +93,7 @@ private:
|
||||
friend class VstEffectControlDialog;
|
||||
friend class manageVSTEffectView;
|
||||
|
||||
bool m_vstGuiVisible;
|
||||
} ;
|
||||
|
||||
|
||||
@@ -112,7 +110,7 @@ public:
|
||||
protected slots:
|
||||
void syncPlugin( void );
|
||||
void displayAutomatedOnly( void );
|
||||
void setParameter( void );
|
||||
void setParameter( Model * action );
|
||||
void closeWindow();
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,6 +12,8 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WERROR_FLAGS} -fexceptions")
|
||||
|
||||
IF(LMMS_BUILD_WIN32 AND NOT MSVC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -Dexprtk_disable_enhanced_features")
|
||||
ELSEIF(LMMS_BUILD_WIN32 AND MSVC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
||||
ENDIF()
|
||||
|
||||
BUILD_PLUGIN(xpressive
|
||||
|
||||
@@ -48,12 +48,14 @@
|
||||
|
||||
#include "ExprSynth.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
Plugin::Descriptor PLUGIN_EXPORT xpressive_plugin_descriptor = { STRINGIFY(
|
||||
PLUGIN_NAME), "X-Pressive", QT_TRANSLATE_NOOP("pluginBrowser",
|
||||
"Mathematical expression parser"), "Orr Dvori", 0x0100,
|
||||
Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL };
|
||||
PLUGIN_NAME), "Xpressive", QT_TRANSLATE_NOOP("pluginBrowser",
|
||||
"Mathematical expression parser"), "Orr Dvori", 0x0100,
|
||||
Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL };
|
||||
|
||||
}
|
||||
|
||||
@@ -255,7 +257,6 @@ public:
|
||||
setCenterPointY(14.5);
|
||||
setInnerRadius(4);
|
||||
setOuterRadius(9);
|
||||
setOuterColor(QColor(0x519fff));
|
||||
setTotalAngle(300.0);
|
||||
setLineWidth(3);
|
||||
}
|
||||
@@ -272,17 +273,21 @@ public:
|
||||
|
||||
|
||||
XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
InstrumentView(_instrument, _parent)
|
||||
InstrumentViewFixedSize(_instrument, _parent)
|
||||
|
||||
{
|
||||
const int COL_KNOBS = 194;
|
||||
const int ROW_KNOBSA1 = 26;
|
||||
const int ROW_KNOBSA2 = 26 + 32;
|
||||
const int ROW_KNOBSA3 = 26 + 64;
|
||||
const int ROW_KNOBSP1 = 126;
|
||||
const int ROW_KNOBSP2 = 126 + 32;
|
||||
const int ROW_KNOBREL = 126 + 64;
|
||||
const int ROW_WAVEBTN = 234;
|
||||
const int COL_KNOBS = 191;
|
||||
const int BASE_START = 2;
|
||||
const int ROW_KNOBSA1 = BASE_START;
|
||||
const int ROW_KNOBSA2 = BASE_START + 32;
|
||||
const int ROW_KNOBSA3 = BASE_START + 64;
|
||||
const int ROW_KNOBSP1 = BASE_START + 100;
|
||||
const int ROW_KNOBSP2 = BASE_START + 100 + 32;
|
||||
const int ROW_KNOBREL = BASE_START + 100 + 64;
|
||||
const int ROW_BTN = BASE_START + 85;
|
||||
const int ROW_WAVEBTN = BASE_START + 233 - 26;
|
||||
const int EXPR_TEXT_Y = BASE_START + 102;
|
||||
const int EXPR_TEXT_H = 90;
|
||||
|
||||
setAutoFillBackground(true);
|
||||
QPalette pal;
|
||||
@@ -291,7 +296,7 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
setPalette(pal);
|
||||
|
||||
m_graph = new Graph(this, Graph::LinearStyle, 180, 81);
|
||||
m_graph->move(9, 27);
|
||||
m_graph->move(3, BASE_START + 1);
|
||||
m_graph->setAutoFillBackground(true);
|
||||
m_graph->setGraphColor(QColor(255, 255, 255));
|
||||
m_graph->setEnabled(false);
|
||||
@@ -311,37 +316,37 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
PixmapButton * m_helpBtn;
|
||||
|
||||
m_w1Btn = new PixmapButton(this, NULL);
|
||||
m_w1Btn->move(9, 111);
|
||||
m_w1Btn->move(3, ROW_BTN);
|
||||
m_w1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w1_active"));
|
||||
m_w1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w1_inactive"));
|
||||
ToolTip::add(m_w1Btn, tr("Select oscillator W1"));
|
||||
|
||||
m_w2Btn = new PixmapButton(this, NULL);
|
||||
m_w2Btn->move(32, 111);
|
||||
m_w2Btn->move(26, ROW_BTN);
|
||||
m_w2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w2_active"));
|
||||
m_w2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w2_inactive"));
|
||||
ToolTip::add(m_w2Btn, tr("Select oscillator W2"));
|
||||
|
||||
m_w3Btn = new PixmapButton(this, NULL);
|
||||
m_w3Btn->move(55, 111);
|
||||
m_w3Btn->move(49, ROW_BTN);
|
||||
m_w3Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w3_active"));
|
||||
m_w3Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w3_inactive"));
|
||||
ToolTip::add(m_w3Btn, tr("Select oscillator W3"));
|
||||
|
||||
m_o1Btn = new PixmapButton(this, NULL);
|
||||
m_o1Btn->move(85, 111);
|
||||
m_o1Btn->move(79, ROW_BTN);
|
||||
m_o1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o1_active"));
|
||||
m_o1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o1_inactive"));
|
||||
ToolTip::add(m_o1Btn, tr("Select output O1"));
|
||||
|
||||
m_o2Btn = new PixmapButton(this, NULL);
|
||||
m_o2Btn->move(107, 111);
|
||||
m_o2Btn->move(101, ROW_BTN);
|
||||
m_o2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o2_active"));
|
||||
m_o2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o2_inactive"));
|
||||
ToolTip::add(m_o2Btn, tr("Select output O2"));
|
||||
|
||||
m_helpBtn = new PixmapButton(this, NULL);
|
||||
m_helpBtn->move(139, 111);
|
||||
m_helpBtn->move(133, ROW_BTN);
|
||||
m_helpBtn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("help_active"));
|
||||
m_helpBtn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("help_inactive"));
|
||||
ToolTip::add(m_helpBtn, tr("Open help window"));
|
||||
@@ -357,38 +362,38 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
m_selectedGraphGroup->setModel(&e->selectedGraph());
|
||||
|
||||
m_sinWaveBtn = new PixmapButton(this, tr("Sine wave"));
|
||||
m_sinWaveBtn->move(10, ROW_WAVEBTN);
|
||||
m_sinWaveBtn->move(4, ROW_WAVEBTN);
|
||||
m_sinWaveBtn->setActiveGraphic(embed::getIconPixmap("sin_wave_active"));
|
||||
m_sinWaveBtn->setInactiveGraphic(embed::getIconPixmap("sin_wave_inactive"));
|
||||
ToolTip::add(m_sinWaveBtn, tr("Sine wave"));
|
||||
|
||||
m_moogWaveBtn = new PixmapButton(this, tr("Moog-saw wave"));
|
||||
m_moogWaveBtn->move(10, ROW_WAVEBTN-14);
|
||||
m_moogWaveBtn->move(4, ROW_WAVEBTN-14);
|
||||
m_moogWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap( "moog_saw_wave_active" ) );
|
||||
m_moogWaveBtn->setInactiveGraphic(embed::getIconPixmap("moog_saw_wave_inactive"));
|
||||
ToolTip::add(m_moogWaveBtn, tr("Moog-saw wave"));
|
||||
|
||||
m_expWaveBtn = new PixmapButton(this, tr("Exponential wave"));
|
||||
m_expWaveBtn->move(10 +14, ROW_WAVEBTN-14);
|
||||
m_expWaveBtn->move(4 +14, ROW_WAVEBTN-14);
|
||||
m_expWaveBtn->setActiveGraphic(embed::getIconPixmap( "exp_wave_active" ) );
|
||||
m_expWaveBtn->setInactiveGraphic(embed::getIconPixmap( "exp_wave_inactive" ) );
|
||||
ToolTip::add(m_expWaveBtn, tr("Exponential wave"));
|
||||
|
||||
m_sawWaveBtn = new PixmapButton(this, tr("Saw wave"));
|
||||
m_sawWaveBtn->move(10 + 14 * 2, ROW_WAVEBTN-14);
|
||||
m_sawWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN-14);
|
||||
m_sawWaveBtn->setActiveGraphic(embed::getIconPixmap("saw_wave_active"));
|
||||
m_sawWaveBtn->setInactiveGraphic(embed::getIconPixmap("saw_wave_inactive"));
|
||||
ToolTip::add(m_sawWaveBtn, tr("Saw wave"));
|
||||
|
||||
m_usrWaveBtn = new PixmapButton(this, tr("User-defined wave"));
|
||||
m_usrWaveBtn->move(10 + 14 * 3, ROW_WAVEBTN-14);
|
||||
m_usrWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN-14);
|
||||
m_usrWaveBtn->setActiveGraphic(embed::getIconPixmap("usr_wave_active"));
|
||||
m_usrWaveBtn->setInactiveGraphic(embed::getIconPixmap("usr_wave_inactive"));
|
||||
ToolTip::add(m_usrWaveBtn, tr("User-defined wave"));
|
||||
|
||||
m_triangleWaveBtn = new PixmapButton(this, tr("Triangle wave"));
|
||||
m_triangleWaveBtn->move(10 + 14, ROW_WAVEBTN);
|
||||
m_triangleWaveBtn->move(4 + 14, ROW_WAVEBTN);
|
||||
m_triangleWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap("triangle_wave_active"));
|
||||
m_triangleWaveBtn->setInactiveGraphic(
|
||||
@@ -396,14 +401,14 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
ToolTip::add(m_triangleWaveBtn, tr("Triangle wave"));
|
||||
|
||||
m_sqrWaveBtn = new PixmapButton(this, tr("Square wave"));
|
||||
m_sqrWaveBtn->move(10 + 14 * 2, ROW_WAVEBTN);
|
||||
m_sqrWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN);
|
||||
m_sqrWaveBtn->setActiveGraphic(embed::getIconPixmap("square_wave_active"));
|
||||
m_sqrWaveBtn->setInactiveGraphic(
|
||||
embed::getIconPixmap("square_wave_inactive"));
|
||||
ToolTip::add(m_sqrWaveBtn, tr("Square wave"));
|
||||
|
||||
m_whiteNoiseWaveBtn = new PixmapButton(this, tr("White noise"));
|
||||
m_whiteNoiseWaveBtn->move(10 + 14 * 3, ROW_WAVEBTN);
|
||||
m_whiteNoiseWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN);
|
||||
m_whiteNoiseWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap("white_noise_wave_active"));
|
||||
m_whiteNoiseWaveBtn->setInactiveGraphic(
|
||||
@@ -413,16 +418,16 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
|
||||
m_waveInterpolate = new LedCheckBox("Interpolate", this, tr("WaveInterpolate"),
|
||||
LedCheckBox::Green);
|
||||
m_waveInterpolate->move(120, 230);
|
||||
m_waveInterpolate->move(2, 230);
|
||||
|
||||
m_expressionValidToggle = new LedCheckBox("", this, tr("ExpressionValid"),
|
||||
LedCheckBox::Red);
|
||||
m_expressionValidToggle->move(174, 216);
|
||||
m_expressionValidToggle->move(168, EXPR_TEXT_Y+EXPR_TEXT_H-2);
|
||||
m_expressionValidToggle->setEnabled( false );
|
||||
|
||||
m_expressionEditor = new QPlainTextEdit(this);
|
||||
m_expressionEditor->move(9, 128);
|
||||
m_expressionEditor->resize(180, 90);
|
||||
m_expressionEditor->move(3, EXPR_TEXT_Y);
|
||||
m_expressionEditor->resize(180, EXPR_TEXT_H);
|
||||
|
||||
m_generalPurposeKnob[0] = new XpressiveKnob(this,"A1");
|
||||
m_generalPurposeKnob[0]->setHintText(tr("General purpose 1:"), "");
|
||||
@@ -450,9 +455,16 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
|
||||
|
||||
|
||||
|
||||
m_smoothKnob=new Knob(this,"Smoothness");
|
||||
m_smoothKnob=new Knob(knobStyled, this, "Smoothness");
|
||||
m_smoothKnob->setFixedSize(25, 25);
|
||||
m_smoothKnob->setCenterPointX(12.5);
|
||||
m_smoothKnob->setCenterPointY(12.5);
|
||||
m_smoothKnob->setInnerRadius(4);
|
||||
m_smoothKnob->setOuterRadius(9);
|
||||
m_smoothKnob->setTotalAngle(280.0);
|
||||
m_smoothKnob->setLineWidth(3);
|
||||
m_smoothKnob->setHintText(tr("Smoothness"), "");
|
||||
m_smoothKnob->move(80, 220);
|
||||
m_smoothKnob->move(66, EXPR_TEXT_Y + EXPR_TEXT_H + 4);
|
||||
|
||||
connect(m_generalPurposeKnob[0], SIGNAL(sliderMoved(float)), this,
|
||||
SLOT(expressionChanged()));
|
||||
@@ -746,7 +758,7 @@ void XpressiveView::updateLayout() {
|
||||
|
||||
void XpressiveView::sinWaveClicked() {
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("sinew(t*f)");
|
||||
m_expressionEditor->appendPlainText("sinew(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("sinew(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -754,7 +766,7 @@ void XpressiveView::sinWaveClicked() {
|
||||
|
||||
void XpressiveView::triangleWaveClicked() {
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("trianglew(t*f)");
|
||||
m_expressionEditor->appendPlainText("trianglew(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("trianglew(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -762,7 +774,7 @@ void XpressiveView::triangleWaveClicked() {
|
||||
|
||||
void XpressiveView::sawWaveClicked() {
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("saww(t*f)");
|
||||
m_expressionEditor->appendPlainText("saww(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("saww(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -770,7 +782,7 @@ void XpressiveView::sawWaveClicked() {
|
||||
|
||||
void XpressiveView::sqrWaveClicked() {
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("squarew(t*f)");
|
||||
m_expressionEditor->appendPlainText("squarew(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("squarew(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -784,7 +796,7 @@ void XpressiveView::noiseWaveClicked() {
|
||||
void XpressiveView::moogSawWaveClicked()
|
||||
{
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("moogsaww(t*f)");
|
||||
m_expressionEditor->appendPlainText("moogsaww(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("moogsaww(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -792,7 +804,7 @@ void XpressiveView::moogSawWaveClicked()
|
||||
void XpressiveView::expWaveClicked()
|
||||
{
|
||||
if (m_output_expr)
|
||||
m_expressionEditor->appendPlainText("expw(t*f)");
|
||||
m_expressionEditor->appendPlainText("expw(integrate(f))");
|
||||
else
|
||||
m_expressionEditor->appendPlainText("expw(t)");
|
||||
Engine::getSong()->setModified();
|
||||
@@ -805,8 +817,6 @@ void XpressiveView::usrWaveClicked() {
|
||||
Engine::getSong()->setModified();
|
||||
}
|
||||
|
||||
XpressiveHelpView* XpressiveHelpView::s_instance=0;
|
||||
|
||||
QString XpressiveHelpView::s_helpText=
|
||||
"<b>O1, O2</b> - Two output waves. Panning is controled by PN1 and PN2.<br>"
|
||||
"<b>W1, W2, W3</b> - Wave samples evaluated by expression. In these samples, t variable ranges [0,1).<br>"
|
||||
@@ -861,7 +871,7 @@ QString XpressiveHelpView::s_helpText=
|
||||
|
||||
XpressiveHelpView::XpressiveHelpView():QTextEdit(s_helpText)
|
||||
{
|
||||
setWindowTitle ( "X-Pressive Help" );
|
||||
setWindowTitle ( "Xpressive Help" );
|
||||
setTextInteractionFlags ( Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse );
|
||||
gui->mainWindow()->addWindowedWidget( this );
|
||||
parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false );
|
||||
@@ -874,16 +884,11 @@ void XpressiveView::helpClicked() {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((destructor)) static void module_destroy()
|
||||
{
|
||||
XpressiveHelpView::finalize();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
Plugin * PLUGIN_EXPORT lmms_plugin_main(Model *, void * _data) {
|
||||
return (new Xpressive(static_cast<InstrumentTrack *>(_data)));
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main(Model *m, void *) {
|
||||
return (new Xpressive(static_cast<InstrumentTrack *>(m)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
} ;
|
||||
|
||||
|
||||
class XpressiveView : public InstrumentView
|
||||
class XpressiveView : public InstrumentViewFixedSize
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -206,22 +206,16 @@ class XpressiveHelpView: public QTextEdit
|
||||
public:
|
||||
static XpressiveHelpView* getInstance()
|
||||
{
|
||||
if (!s_instance)
|
||||
{
|
||||
s_instance = new XpressiveHelpView();
|
||||
}
|
||||
return s_instance;
|
||||
static XpressiveHelpView instance;
|
||||
return &instance;
|
||||
}
|
||||
static void finalize()
|
||||
{
|
||||
if (s_instance) { delete s_instance; }
|
||||
}
|
||||
|
||||
private:
|
||||
XpressiveHelpView();
|
||||
static XpressiveHelpView *s_instance;
|
||||
static QString s_helpText;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
130
plugins/Xpressive/Xpressive.svg
Normal file
@@ -0,0 +1,130 @@
|
||||
<?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="17in"
|
||||
height="11in"
|
||||
viewBox="0 0 431.8 279.4"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="Xpressive.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.61780345"
|
||||
inkscape:cx="1006.8716"
|
||||
inkscape:cy="872.08024"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="g956"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:measure-start="234.5,1092.07"
|
||||
inkscape:measure-end="180.984,1024.7"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1025"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="in" />
|
||||
<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(0,-17.6)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccccccscssccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path819"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:0;stroke:none;stroke-width:0.65183502"
|
||||
d="M 85.029931,192.14174 H 72.13582 L 56.369561,164.82578 40.603301,192.14174 H 27.709189 l 22.18276,-38.62122 c -3.259176,-5.78503 -6.681309,-11.65155 -10.2664,-17.59955 -3.544354,-5.94799 -6.212803,-10.61268 -8.005349,-13.99407 -1.751807,-3.3814 -2.74993,-5.2758 -2.994369,-5.68319 -0.203692,-0.44814 -0.203692,-0.89628 0,-1.34442 0.529617,-1.09997 1.833288,-1.58884 3.911012,-1.46662 h 7.333145 l 16.499573,28.8437 16.499574,-28.8437 h 7.638692 c 1.914764,0 3.096215,0.38702 3.544352,1.16108 0.448135,0.73332 0.549987,1.3444 0.305548,1.83329 -0.244441,0.48886 -0.896272,1.64994 -1.955505,3.48325 -1.059232,1.83328 -2.485121,4.27765 -4.277667,7.33313 -1.751808,3.01474 -3.523983,6.04984 -5.31653,9.10532 -1.751807,3.05548 -3.483244,6.04984 -5.194309,8.98311 -1.711066,2.8925 -3.299915,5.62206 -4.766544,8.18867 7.39425,12.87374 14.788506,25.74748 22.182759,38.62122 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path821"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 98.901794,135.55432 q 3.972116,-2.87215 8.860876,-2.87215 h 4.27767 q 7.76091,0 12.40524,4.461 4.64432,4.39988 4.64432,12.34413 v 24.4438 q 0,12.77189 -8.61645,16.74402 -2.99437,1.3444 -7.21091,1.3444 h -6.72205 q -3.97212,0 -6.722053,-2.99437 v 29.88257 H 89.246488 l 0.0611,-86.22555 h 9.594197 z m 19.738376,37.58236 v -22.18277 q 0,-4.76654 -1.03886,-6.35537 -1.89439,-2.93327 -6.29429,-2.93327 h -5.25541 q -1.8944,0 -3.42213,0.97775 -2.811043,1.71107 -2.811043,3.54435 v 30.7381 q 0,1.83329 1.588843,3.36102 2.87215,2.68882 4.64433,2.68882 h 5.25541 q 6.11096,0 7.0276,-6.04984 0.30555,-1.77217 0.30555,-3.78879 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path823"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 162.92377,141.60416 -6.17207,-0.0611 q -7.6998,0 -10.02196,5.56097 -0.79442,1.8944 -0.79442,4.33878 v 40.63783 h -10.44973 l -0.0611,-54.14304 q -2.68882,0 -2.68882,-2.01661 v -3.54436 h 12.03858 v 5.56097 q 0.85553,-2.44438 3.11658,-4.03324 2.26105,-1.58884 4.82765,-1.58884 h 10.20529 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path825"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 208.51148,178.45321 q -0.1833,9.22754 -7.14982,12.58857 -2.32216,1.09996 -5.31653,1.09996 h -14.48296 q -5.43874,0 -9.0442,-3.97211 -3.54436,-3.8499 -3.54436,-9.34977 v -33.3658 q 0,-5.43874 3.17769,-9.22754 3.48325,-4.03323 8.79978,-4.03323 h 15.52183 q 5.43873,0 8.79977,4.33878 3.11658,3.97212 3.11658,9.53308 v 7.94424 q 0,5.37765 -2.87215,9.04422 -3.05549,3.97211 -8.43311,3.97211 h -17.84398 v 11.06083 q 0,4.88876 4.94987,4.88876 h 9.28866 q 2.07772,0 3.2999,-1.16108 1.28331,-1.22219 1.22218,-3.36102 z m -24.32159,-36.78794 q -4.94987,0 -4.94987,5.1332 v 11.18304 H 192.623 q 2.32216,0 3.91101,-1.2833 1.64997,-1.3444 1.64997,-3.8499 v -6.29428 q 0,-2.5666 -1.64997,-3.72768 -1.58885,-1.16108 -3.91101,-1.16108 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path827"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 242.67037,145.51517 q 0.1222,-3.42213 -4.21656,-3.42213 h -7.63868 q -5.25542,0 -4.76656,7.14981 0.12219,1.77218 0.12219,3.29991 0,4.58322 4.64434,4.58322 h 10.69417 q 5.49985,0 8.92198,3.97212 3.36103,3.8499 3.36103,9.28865 v 8.18868 q 0,5.62208 -3.60547,9.53309 -3.72766,4.09433 -9.28864,4.09433 h -13.4441 q -5.98874,0 -9.47199,-3.91101 -3.2999,-3.78878 -3.2999,-9.77753 h 10.51084 q -0.12219,2.13885 1.03887,3.05548 1.22218,0.85554 3.17769,0.85554 h 8.86088 q 4.64433,0 4.64433,-4.58322 v -6.11095 q 0,-4.76654 -4.64433,-4.76654 H 228.1874 q -5.56098,0 -9.22756,-3.42213 -3.66656,-3.48325 -3.66656,-9.04421 v -8.92199 q 0,-5.49986 3.29991,-9.28866 3.60547,-4.03322 8.9831,-4.03322 h 13.13856 q 5.62207,0 9.16642,3.84989 3.2999,3.66657 3.2999,9.41087 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path829"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 287.16347,145.51517 q 0.12219,-3.42213 -4.21658,-3.42213 h -7.63867 q -5.25544,0 -4.76656,7.14981 0.1222,1.77218 0.1222,3.29991 0,4.58322 4.64434,4.58322 h 10.69416 q 5.49985,0 8.92198,3.97212 3.36104,3.8499 3.36104,9.28865 v 8.18868 q 0,5.62208 -3.60547,9.53309 -3.72768,4.09433 -9.28865,4.09433 h -13.4441 q -5.98873,0 -9.47198,-3.91101 -3.29991,-3.78878 -3.29991,-9.77753 h 10.51082 q -0.12219,2.13885 1.03887,3.05548 1.2222,0.85554 3.1777,0.85554 h 8.86089 q 4.64431,0 4.64431,-4.58322 v -6.11095 q 0,-4.76654 -4.64431,-4.76654 h -10.08309 q -5.56094,0 -9.22752,-3.42213 -3.66657,-3.48325 -3.66657,-9.04421 v -8.92199 q 0,-5.49986 3.29991,-9.28866 3.60548,-4.03322 8.98311,-4.03322 h 13.13855 q 5.62207,0 9.16642,3.84989 3.29991,3.66657 3.29991,9.41087 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path831"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 312.24186,114.71597 q 6.72205,0 6.72205,6.84427 0,6.90537 -6.72205,6.90537 -3.29991,0 -5.07211,-1.77218 -1.77215,-1.83328 -1.77215,-5.13319 0,-3.29993 1.77215,-5.0721 1.7722,-1.77217 5.07211,-1.77217 z m 5.13318,77.12023 h -10.51082 v -59.39847 h 10.51082 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path833"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 345.66878,178.02544 q 0.61108,-2.5666 10.93861,-45.5266 h 6.23315 q 2.13884,0 3.23882,1.9555 0.36666,0.54999 0.36666,1.2833 0,0.67222 -0.61111,3.29992 -0.54998,2.5666 -1.52772,6.29429 -0.91664,3.72768 -2.13885,8.31089 -1.22218,4.58322 -2.56658,9.34976 -1.28331,4.76654 -2.56661,9.47198 -1.28331,4.64432 -2.38326,8.55533 -2.56662,9.04421 -2.99438,10.75528 h -11.97747 q -0.42778,-1.40552 -1.34442,-4.461 -0.85552,-3.05548 -2.07771,-7.08871 -1.2222,-4.09433 -2.62772,-8.79976 -1.40551,-4.76655 -2.81103,-9.53309 -1.40553,-4.76655 -2.68883,-9.28865 -1.2833,-4.52212 -2.26104,-8.12758 -2.26105,-8.06644 -2.26105,-9.22753 0,-1.16108 0.97775,-1.95551 1.03885,-0.79442 2.26104,-0.79442 h 6.78316 q 6.84427,25.6049 12.03859,45.5266 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path835"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#eff3ff;fill-opacity:1;stroke:#001800;stroke-width:0.65183502;stroke-opacity:1"
|
||||
d="m 411.48372,178.45321 q -0.18328,9.22754 -7.14981,12.58857 -2.32217,1.09996 -5.31654,1.09996 h -14.48295 q -5.43876,0 -9.04421,-3.97211 -3.54437,-3.8499 -3.54437,-9.34977 v -33.3658 q 0,-5.43874 3.17771,-9.22754 3.48322,-4.03323 8.79976,-4.03323 h 15.52182 q 5.43876,0 8.79979,4.33878 3.11659,3.97212 3.11659,9.53308 v 7.94424 q 0,5.37765 -2.87215,9.04422 -3.0555,3.97211 -8.43312,3.97211 h -17.84399 v 11.06083 q 0,4.88876 4.94987,4.88876 h 9.28864 q 2.07773,0 3.29994,-1.16108 1.28327,-1.22219 1.22218,-3.36102 z m -24.3216,-36.78794 q -4.94987,0 -4.94987,5.1332 v 11.18304 h 13.38299 q 2.32217,0 3.91102,-1.2833 1.64993,-1.3444 1.64993,-3.8499 v -6.29428 q 0,-2.5666 -1.64993,-3.72768 -1.58885,-1.16108 -3.91102,-1.16108 z" />
|
||||
<path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#50626e;fill-opacity:1;stroke:#000000;stroke-width:0.65183496;stroke-opacity:1"
|
||||
d="m 31.793889,113.41583 c -1.648687,0.0267 -2.704098,0.52071 -3.167508,1.48318 -0.203699,0.44815 -0.203699,0.89628 0,1.34442 0.244438,0.40739 1.242553,2.30179 2.994367,5.68318 1.792541,3.3814 4.460996,8.04609 8.005349,13.99409 2.997776,4.97358 5.874553,9.88684 8.644447,14.74649 l 6.472519,-11.23524 -14.872528,-25.99957 h -7.333144 c -0.259717,-0.0152 -0.507975,-0.0203 -0.743502,-0.0165 z m 32.622309,42.83525 -6.47379,11.29889 14.193961,24.59149 H 85.030481 C 78.159057,180.178 71.287615,168.21454 64.416198,156.25108 Z"
|
||||
id="path819-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g956"
|
||||
style="stroke:#000000;stroke-opacity:1"
|
||||
transform="matrix(2.4636285,0,0,2.4636285,-59.948071,75.031414)">
|
||||
<path
|
||||
d="m 47.213951,36.448011 -6.399609,11.087694 h -5.233789 l 9.004101,-15.676562 2.629297,-4.564063 6.697266,-11.707812 2.980857,-5.060626 138.949186,-0.0013 c 0.79306,-7e-6 0.30296,4.198952 -0.53489,4.167335 l -135.515802,-4e-6 c 0,0 -1.116851,1.91157 -1.21607,2.110007 -0.09922,0.198437 -0.363802,0.669726 -0.79375,1.413867 -0.429948,0.744141 -1.008724,1.736328 -1.736328,2.976562 -0.711068,1.223698 -1.430404,2.455664 -2.158008,3.695899 -0.711068,1.240234 -1.413867,2.455665 -2.108398,3.64629 -0.694531,1.174088 -1.339453,2.282031 -1.934766,3.323827 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#41bbff;fill-opacity:1;stroke:#000000;stroke-width:0.26465029;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round"
|
||||
id="path819-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccsccssccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccc"
|
||||
id="path819-7-3"
|
||||
d="m 28.89259,32.41518 c -0.669211,0.01085 -1.097608,0.211356 -1.285708,0.602031 -0.08268,0.181901 -0.08268,0.363802 0,0.545703 0.09922,0.165365 0.504359,0.93431 1.215429,2.306836 0.727602,1.372526 1.810743,3.26595 3.249415,5.680273 1.216813,2.018806 2.384512,4.013124 3.508827,5.985682 l 2.62723,-4.560446 -6.036839,-10.553361 h -2.976562 c -0.105421,-0.0062 -0.20619,-0.0083 -0.301792,-0.0067 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#009acd;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-opacity:1;stroke-linejoin:round;stroke-linecap:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
106
plugins/Xpressive/Xpressive_logo.svg
Normal file
@@ -0,0 +1,106 @@
|
||||
<?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="10in"
|
||||
height="10in"
|
||||
viewBox="0 0 254 254"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="Xpressive_square.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.61780345"
|
||||
inkscape:cx="457.11509"
|
||||
inkscape:cy="666.64265"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:measure-start="234.5,1092.07"
|
||||
inkscape:measure-end="180.984,1024.7"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1025"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="in" />
|
||||
<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(0,-43)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccccccscssccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path819"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:0;stroke:none;stroke-width:1.22181463"
|
||||
d="M 146.74936,246.42818 H 122.58033 L 93.027698,195.22652 63.475055,246.42818 H 39.306034 l 41.579877,-72.39251 c -6.109073,-10.84359 -12.5236,-21.83994 -19.243577,-32.989 -6.643618,-11.14906 -11.645421,-19.89265 -15.005411,-26.23082 -3.283627,-6.33817 -5.154532,-9.88907 -5.612714,-10.65269 -0.381805,-0.84 -0.381805,-1.68001 0,-2.52001 0.992726,-2.061805 3.436357,-2.978157 7.330891,-2.749069 H 62.100517 L 93.027698,152.95937 123.95488,98.894081 h 14.31815 c 3.58906,0 5.80362,0.725445 6.6436,2.176359 0.84001,1.37455 1.03091,2.51998 0.57274,3.43635 -0.45819,0.91634 -1.67999,3.0927 -3.66545,6.52909 -1.98545,3.43634 -4.65817,8.01812 -8.01815,13.74539 -3.28363,5.6509 -6.60544,11.33996 -9.96544,17.06722 -3.28362,5.72727 -6.52907,11.33996 -9.73632,16.83815 -3.20727,5.42177 -6.18544,10.53811 -8.93453,15.34903 13.85995,24.13085 27.71991,48.26168 41.57988,72.39251 z" />
|
||||
<path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#50626e;fill-opacity:1;stroke:#000000;stroke-width:1.22181451;stroke-opacity:1"
|
||||
d="m 46.96249,98.862515 c -3.090337,0.05013 -5.068624,0.976029 -5.93725,2.780105 -0.381818,0.84003 -0.381818,1.68001 0,2.52002 0.458181,0.76362 2.32907,4.31453 5.61271,10.65268 3.359981,6.33817 8.361795,15.08177 15.005413,26.23085 5.619099,9.3226 11.011397,18.53211 16.20335,27.64116 L 89.978952,147.62774 62.101542,98.893528 H 48.356127 c -0.486819,-0.02856 -0.95216,-0.03805 -1.393637,-0.03093 z m 61.14801,80.291385 -12.134621,21.1789 26.605491,46.09485 h 24.16902 C 133.87043,224.00307 120.99044,201.57848 108.1105,179.1539 Z"
|
||||
id="path819-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g956"
|
||||
style="stroke:#000000;stroke-opacity:1"
|
||||
transform="matrix(4.6178822,0,0,4.6178822,-125.00076,26.913875)">
|
||||
<path
|
||||
d="m 47.213951,36.448011 -6.399609,11.087694 h -5.233789 l 9.004101,-15.676562 2.629297,-4.564063 6.697266,-11.707812 2.980857,-5.060626 24.385361,-0.0013 c 0.79306,-4.2e-5 0.30296,4.198952 -0.53489,4.167335 l -20.951977,-4e-6 c 0,0 -1.116851,1.91157 -1.21607,2.110007 -0.09922,0.198437 -0.363802,0.669726 -0.79375,1.413867 -0.429948,0.744141 -1.008724,1.736328 -1.736328,2.976562 -0.711068,1.223698 -1.430404,2.455664 -2.158008,3.695899 -0.711068,1.240234 -1.413867,2.455665 -2.108398,3.64629 -0.694531,1.174088 -1.339453,2.282031 -1.934766,3.323827 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#41bbff;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-opacity:1"
|
||||
id="path819-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccsccssccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccc"
|
||||
id="path819-7-3"
|
||||
d="m 28.89259,32.41518 c -0.669211,0.01085 -1.097608,0.211356 -1.285708,0.602031 -0.08268,0.181901 -0.08268,0.363802 0,0.545703 0.09922,0.165365 0.504359,0.93431 1.215429,2.306836 0.727602,1.372526 1.810743,3.26595 3.249415,5.680273 1.216813,2.018806 2.384512,4.013124 3.508827,5.985682 l 2.62723,-4.560446 -6.036839,-10.553361 h -2.976562 c -0.105421,-0.0062 -0.20619,-0.0083 -0.301792,-0.0067 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.79999924px;line-height:1.25;font-family:Uroob;-inkscape-font-specification:Uroob;letter-spacing:0px;word-spacing:0px;fill:#009acd;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.5626235;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 152.95675,100.4412 v 5.70357 139.55424 h 92.87918 V 100.4412 Z m 11.40714,11.40486 h 70.06718 v 122.44809 h -70.06718 z"
|
||||
id="rect825"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<style
|
||||
id="style854"
|
||||
type="text/css">
|
||||
.st0{fill:#E0995E;}
|
||||
.st1{opacity:0.2;}
|
||||
.st2{fill:#231F20;}
|
||||
.st3{fill:#4F5D73;}
|
||||
.st4{fill:none;stroke:#FFFFFF;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
|
||||
.st5{fill:none;stroke:#E0E0D1;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
|
||||
.st6{fill:none;stroke:#F5CF87;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
|
||||
</style>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 546 B |
|
Before Width: | Height: | Size: 806 B After Width: | Height: | Size: 549 B |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 653 B |
|
Before Width: | Height: | Size: 602 B After Width: | Height: | Size: 589 B |
|
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 549 B After Width: | Height: | Size: 554 B |
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 715 B |
|
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 662 B |
|
Before Width: | Height: | Size: 771 B After Width: | Height: | Size: 705 B |
|
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 652 B |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
@@ -45,7 +45,7 @@
|
||||
#include "DataFile.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
#include "plugin_export.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -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 )
|
||||
{
|
||||
@@ -505,7 +505,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
|
||||
"loop_pingpong_on" ) );
|
||||
m_loopPingPongButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"loop_pingpong_off" ) );
|
||||
ToolTip::add( m_loopPingPongButton, tr( "Enable loop" ) );
|
||||
ToolTip::add( m_loopPingPongButton, tr( "Enable ping-pong loop" ) );
|
||||
|
||||
m_loopGroup = new automatableButtonGroup( this );
|
||||
m_loopGroup->addButton( m_loopOffButton );
|
||||
@@ -753,6 +753,7 @@ AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _
|
||||
|
||||
m_graph.fill( Qt::transparent );
|
||||
update();
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
@@ -769,7 +770,7 @@ void AudioFileProcessorWaveView::isPlaying( f_cnt_t _current_frame )
|
||||
|
||||
void AudioFileProcessorWaveView::enterEvent( QEvent * _e )
|
||||
{
|
||||
QApplication::setOverrideCursor( Qt::OpenHandCursor );
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
@@ -777,10 +778,7 @@ void AudioFileProcessorWaveView::enterEvent( QEvent * _e )
|
||||
|
||||
void AudioFileProcessorWaveView::leaveEvent( QEvent * _e )
|
||||
{
|
||||
while( QApplication::overrideCursor() )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
@@ -808,7 +806,7 @@ void AudioFileProcessorWaveView::mousePressEvent( QMouseEvent * _me )
|
||||
else
|
||||
{
|
||||
m_draggingType = wave;
|
||||
QApplication::setOverrideCursor( Qt::ClosedHandCursor );
|
||||
updateCursor(_me);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +818,7 @@ void AudioFileProcessorWaveView::mouseReleaseEvent( QMouseEvent * _me )
|
||||
m_isDragging = false;
|
||||
if( m_draggingType == wave )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
updateCursor(_me);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,22 +829,7 @@ void AudioFileProcessorWaveView::mouseMoveEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( ! m_isDragging )
|
||||
{
|
||||
const bool is_size_cursor =
|
||||
QApplication::overrideCursor()->shape() == Qt::SizeHorCursor;
|
||||
|
||||
if( isCloseTo( _me->x(), m_startFrameX ) ||
|
||||
isCloseTo( _me->x(), m_endFrameX ) ||
|
||||
isCloseTo( _me->x(), m_loopFrameX ) )
|
||||
{
|
||||
if( ! is_size_cursor )
|
||||
{
|
||||
QApplication::setOverrideCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
}
|
||||
else if( is_size_cursor )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
updateCursor(_me);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1219,6 +1202,24 @@ void AudioFileProcessorWaveView::reverse()
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::updateCursor( QMouseEvent * _me )
|
||||
{
|
||||
bool const waveIsDragged = m_isDragging && (m_draggingType == wave);
|
||||
bool const pointerCloseToStartEndOrLoop = (_me != nullptr ) &&
|
||||
( isCloseTo( _me->x(), m_startFrameX ) ||
|
||||
isCloseTo( _me->x(), m_endFrameX ) ||
|
||||
isCloseTo( _me->x(), m_loopFrameX ) );
|
||||
|
||||
if( !m_isDragging && pointerCloseToStartEndOrLoop)
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
else if( waveIsDragged )
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
else
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::knob::slideTo( double _v, bool _check_bound )
|
||||
{
|
||||
@@ -1277,10 +1278,9 @@ extern "C"
|
||||
{
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *, void * _data )
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main(Model * model, void *)
|
||||
{
|
||||
return new audioFileProcessor(
|
||||
static_cast<InstrumentTrack *>( _data ) );
|
||||
return new audioFileProcessor(static_cast<InstrumentTrack *>(model));
|
||||
}
|
||||
|
||||
|
||||
|
||||