Merge branch 'master' into groove

This commit is contained in:
Hyunjin Song
2019-11-19 15:09:51 +09:00
739 changed files with 53261 additions and 30641 deletions

View File

@@ -26,7 +26,7 @@
#include "Amplifier.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{

View File

@@ -25,7 +25,7 @@
#include "BassBooster.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{

View File

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

View File

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

View File

@@ -27,6 +27,7 @@
#include "CrossoverEQ.h"
#include "lmms_math.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{

View File

@@ -26,7 +26,7 @@
#include "Engine.h"
#include "embed.h"
#include "interpolation.h"
#include "plugin_export.h"
extern "C"
{

View File

@@ -27,7 +27,7 @@
#include "embed.h"
#include "BasicFilters.h"
#include "plugin_export.h"
extern "C"
{

View File

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

View File

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

View File

@@ -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"
{

View File

@@ -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();
}

View File

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

View File

@@ -24,7 +24,9 @@
#include "FlangerEffect.h"
#include "Engine.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,6 +19,8 @@
#include "BBTrackContainer.h"
#include "Instrument.h"
#include "plugin_export.h"
#define MAX_LAYERS 4
extern "C"
{

View File

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

View File

@@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -25,7 +25,7 @@
#include "MultitapEcho.h"
#include "embed.h"
#include "plugin_export.h"
extern "C"
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,75 @@
/*
* Analyzer.cpp - definition of Analyzer class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014-2017, David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "Analyzer.h"
#include "embed.h"
#include "plugin_export.h"
extern "C" {
Plugin::Descriptor PLUGIN_EXPORT analyzer_plugin_descriptor =
{
"spectrumanalyzer",
"Spectrum Analyzer",
QT_TRANSLATE_NOOP("pluginBrowser", "A graphical spectrum analyzer."),
"Martin Pavelek <he29/dot/HS/at/gmail/dot/com>",
0x0100,
Plugin::Effect,
new PluginPixmapLoader("logo"),
NULL,
NULL
};
}
Analyzer::Analyzer(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) :
Effect(&analyzer_plugin_descriptor, parent, key),
m_processor(&m_controls),
m_controls(this)
{
}
// Take audio data and pass them to the spectrum processor.
// Skip processing if the controls dialog isn't visible, it would only waste CPU cycles.
bool Analyzer::processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count)
{
if (!isEnabled() || !isRunning ()) {return false;}
if (m_controls.isViewVisible()) {m_processor.analyse(buffer, frame_count);}
return isRunning();
}
extern "C" {
// needed for getting plugin out of shared lib
PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *parent, void *data)
{
return new Analyzer(parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(data));
}
}

View File

@@ -1,7 +1,9 @@
/*
* SpectrumAnalyzerControlDialog.h - view for spectrum analyzer
/* Analyzer.h - declaration of Analyzer class.
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014-2017, David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -22,32 +24,30 @@
*
*/
#ifndef _SPECTRUM_ANALYZER_CONTROL_DIALOG_H
#define _SPECTRUM_ANALYZER_CONTROL_DIALOG_H
#ifndef ANALYZER_H
#define ANALYZER_H
#include "EffectControlDialog.h"
#include "Effect.h"
#include "SaControls.h"
#include "SaProcessor.h"
class SpectrumAnalyzerControls;
class SpectrumAnalyzerControlDialog : public EffectControlDialog
//! Top level class; handles LMMS interface and feeds data to the data processor.
class Analyzer : public Effect
{
Q_OBJECT
public:
SpectrumAnalyzerControlDialog( SpectrumAnalyzerControls* controls );
virtual ~SpectrumAnalyzerControlDialog()
{
}
Analyzer(Model *parent, const Descriptor::SubPluginFeatures::Key *key);
virtual ~Analyzer() {};
bool processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count) override;
EffectControls *controls() override {return &m_controls;}
SaProcessor *getProcessor() {return &m_processor;}
private:
virtual void paintEvent( QPaintEvent* event );
SaProcessor m_processor;
SaControls m_controls;
};
SpectrumAnalyzerControls* m_controls;
#endif // ANALYZER_H
QPixmap m_logXAxis;
QPixmap m_logYAxis;
} ;
#endif

View File

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

View File

@@ -0,0 +1,19 @@
# Spectrum Analyzer plugin
## Overview
This plugin consists of three widgets and back-end code to provide them with required data.
The top-level widget is SaControlDialog. It populates a configuration widget (created dynamically) and instantiates spectrum display widgets. Its main back-end class is SaControls, which holds all configuration values and globally valid constants (e.g. range definitions).
SaSpectrumDisplay and SaWaterfallDisplay show the result of spectrum analysis. Their main back-end class is SaProcessor, which performs FFT analysis on data received from the Analyzer class, which in turn handles the interface with LMMS.
## Changelog
1.0.1 2019-06-02
- code style changes
- added tool-tips
- use const for unmodified arrays passed to fft_helpers
1.0.0 2019-04-07
- initial release

View File

@@ -0,0 +1,144 @@
/*
* SaControls.cpp - definition of SaControls class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SaControls.h"
#include <QtXml/QDomElement>
#include "Analyzer.h"
#include "SaControlsDialog.h"
SaControls::SaControls(Analyzer *effect) :
EffectControls(effect),
m_effect(effect),
// initialize bool models and set default values
m_pauseModel(false, this, tr("Pause")),
m_refFreezeModel(false, this, tr("Reference freeze")),
m_waterfallModel(false, this, tr("Waterfall")),
m_smoothModel(false, this, tr("Averaging")),
m_stereoModel(false, this, tr("Stereo")),
m_peakHoldModel(false, this, tr("Peak hold")),
m_logXModel(true, this, tr("Logarithmic frequency")),
m_logYModel(true, this, tr("Logarithmic amplitude")),
// default values of combo boxes are set after they are populated
m_freqRangeModel(this, tr("Frequency range")),
m_ampRangeModel(this, tr("Amplitude range")),
m_blockSizeModel(this, tr("FFT block size")),
m_windowModel(this, tr("FFT window type"))
{
// Frequency and amplitude ranges; order must match
// FREQUENCY_RANGES and AMPLITUDE_RANGES defined in SaControls.h
m_freqRangeModel.addItem(tr("Full (auto)"));
m_freqRangeModel.addItem(tr("Audible"));
m_freqRangeModel.addItem(tr("Bass"));
m_freqRangeModel.addItem(tr("Mids"));
m_freqRangeModel.addItem(tr("High"));
m_freqRangeModel.setValue(m_freqRangeModel.findText(tr("Full (auto)")));
m_ampRangeModel.addItem(tr("Extended"));
m_ampRangeModel.addItem(tr("Default"));
m_ampRangeModel.addItem(tr("Audible"));
m_ampRangeModel.addItem(tr("Noise"));
m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Default")));
// FFT block size labels are generated automatically, based on
// FFT_BLOCK_SIZES vector defined in fft_helpers.h
for (unsigned int i = 0; i < FFT_BLOCK_SIZES.size(); i++)
{
if (i == 0)
{
m_blockSizeModel.addItem((std::to_string(FFT_BLOCK_SIZES[i]) + " ").c_str() + tr("(High time res.)"));
}
else if (i == FFT_BLOCK_SIZES.size() - 1)
{
m_blockSizeModel.addItem((std::to_string(FFT_BLOCK_SIZES[i]) + " ").c_str() + tr("(High freq. res.)"));
}
else
{
m_blockSizeModel.addItem(std::to_string(FFT_BLOCK_SIZES[i]).c_str());
}
}
m_blockSizeModel.setValue(m_blockSizeModel.findText("2048"));
// Window type order must match FFT_WINDOWS defined in fft_helpers.h
m_windowModel.addItem(tr("Rectangular (Off)"));
m_windowModel.addItem(tr("Blackman-Harris (Default)"));
m_windowModel.addItem(tr("Hamming"));
m_windowModel.addItem(tr("Hanning"));
m_windowModel.setValue(m_windowModel.findText(tr("Blackman-Harris (Default)")));
// Colors
// Background color is defined by Qt / theme.
// Make sure the sum of colors for L and R channel stays lower or equal
// to 255. Otherwise the Waterfall pixels may overflow back to 0 even when
// the input signal isn't clipping (over 1.0).
m_colorL = QColor(51, 148, 204, 135);
m_colorR = QColor(204, 107, 51, 135);
m_colorMono = QColor(51, 148, 204, 204);
m_colorBG = QColor(7, 7, 7, 255); // ~20 % gray (after gamma correction)
m_colorGrid = QColor(30, 34, 38, 255); // ~40 % gray (slightly cold / blue)
m_colorLabels = QColor(192, 202, 212, 255); // ~90 % gray (slightly cold / blue)
}
// Create the SaControlDialog widget which handles display of GUI elements.
EffectControlDialog* SaControls::createView()
{
return new SaControlsDialog(this, m_effect->getProcessor());
}
void SaControls::loadSettings(const QDomElement &_this)
{
m_waterfallModel.loadSettings(_this, "Waterfall");
m_smoothModel.loadSettings(_this, "Smooth");
m_stereoModel.loadSettings(_this, "Stereo");
m_peakHoldModel.loadSettings(_this, "PeakHold");
m_logXModel.loadSettings(_this, "LogX");
m_logYModel.loadSettings(_this, "LogY");
m_freqRangeModel.loadSettings(_this, "RangeX");
m_ampRangeModel.loadSettings(_this, "RangeY");
m_blockSizeModel.loadSettings(_this, "BlockSize");
m_windowModel.loadSettings(_this, "WindowType");
}
void SaControls::saveSettings(QDomDocument &doc, QDomElement &parent)
{
m_waterfallModel.saveSettings(doc, parent, "Waterfall");
m_smoothModel.saveSettings(doc, parent, "Smooth");
m_stereoModel.saveSettings(doc, parent, "Stereo");
m_peakHoldModel.saveSettings(doc, parent, "PeakHold");
m_logXModel.saveSettings(doc, parent, "LogX");
m_logYModel.saveSettings(doc, parent, "LogY");
m_freqRangeModel.saveSettings(doc, parent, "RangeX");
m_ampRangeModel.saveSettings(doc, parent, "RangeY");
m_blockSizeModel.saveSettings(doc, parent, "BlockSize");
m_windowModel.saveSettings(doc, parent, "WindowType");
}

View File

@@ -0,0 +1,126 @@
/*
* SaControls.h - declaration of SaControls class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SACONTROLS_H
#define SACONTROLS_H
#include "ComboBoxModel.h"
#include "EffectControls.h"
//#define SA_DEBUG 1 // define SA_DEBUG to enable performance measurements
// Frequency ranges (in Hz).
// Full range is defined by LOWEST_LOG_FREQ and current sample rate.
const int LOWEST_LOG_FREQ = 10; // arbitrary low limit for log. scale, >1
enum FREQUENCY_RANGES
{
FRANGE_FULL = 0,
FRANGE_AUDIBLE,
FRANGE_BASS,
FRANGE_MIDS,
FRANGE_HIGH
};
const int FRANGE_AUDIBLE_START = 20;
const int FRANGE_AUDIBLE_END = 20000;
const int FRANGE_BASS_START = 20;
const int FRANGE_BASS_END = 300;
const int FRANGE_MIDS_START = 200;
const int FRANGE_MIDS_END = 5000;
const int FRANGE_HIGH_START = 4000;
const int FRANGE_HIGH_END = 20000;
// Amplitude ranges.
// Reference: sine wave from -1.0 to 1.0 = 0 dB.
// I.e. if master volume is 100 %, positive values signify clipping.
// Doubling or halving the amplitude produces 3 dB difference.
enum AMPLITUDE_RANGES
{
ARANGE_EXTENDED = 0,
ARANGE_DEFAULT,
ARANGE_AUDIBLE,
ARANGE_NOISE
};
const int ARANGE_EXTENDED_START = -80;
const int ARANGE_EXTENDED_END = 20;
const int ARANGE_DEFAULT_START = -30;
const int ARANGE_DEFAULT_END = 0;
const int ARANGE_AUDIBLE_START = -50;
const int ARANGE_AUDIBLE_END = 10;
const int ARANGE_NOISE_START = -60;
const int ARANGE_NOISE_END = -20;
class Analyzer;
// Holds all the configuration values
class SaControls : public EffectControls
{
Q_OBJECT
public:
explicit SaControls(Analyzer* effect);
virtual ~SaControls() {}
EffectControlDialog* createView() override;
void saveSettings (QDomDocument& doc, QDomElement& parent) override;
void loadSettings (const QDomElement &_this) override;
QString nodeName() const override {return "Analyzer";}
int controlCount() override {return 12;}
private:
Analyzer *m_effect;
BoolModel m_pauseModel;
BoolModel m_refFreezeModel;
BoolModel m_waterfallModel;
BoolModel m_smoothModel;
BoolModel m_stereoModel;
BoolModel m_peakHoldModel;
BoolModel m_logXModel;
BoolModel m_logYModel;
ComboBoxModel m_freqRangeModel;
ComboBoxModel m_ampRangeModel;
ComboBoxModel m_blockSizeModel;
ComboBoxModel m_windowModel;
QColor m_colorL;
QColor m_colorR;
QColor m_colorMono;
QColor m_colorBG;
QColor m_colorGrid;
QColor m_colorLabels;
friend class SaControlsDialog;
friend class SaSpectrumView;
friend class SaWaterfallView;
friend class SaProcessor;
};
#endif // SACONTROLS_H

View File

@@ -0,0 +1,227 @@
/*
* SaControlsDialog.cpp - definition of SaControlsDialog class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SaControlsDialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QSizePolicy>
#include <QSplitter>
#include <QWidget>
#include "ComboBox.h"
#include "ComboBoxModel.h"
#include "embed.h"
#include "Engine.h"
#include "LedCheckbox.h"
#include "PixmapButton.h"
#include "SaControls.h"
#include "SaProcessor.h"
// The entire GUI layout is built here.
SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) :
EffectControlDialog(controls),
m_controls(controls),
m_processor(processor)
{
// Top level placement of sections is handled by QSplitter widget.
QHBoxLayout *master_layout = new QHBoxLayout;
QSplitter *display_splitter = new QSplitter(Qt::Vertical);
master_layout->addWidget(display_splitter);
master_layout->setContentsMargins(2, 6, 2, 8);
setLayout(master_layout);
// QSplitter top: configuration section
QWidget *config_widget = new QWidget;
QGridLayout *config_layout = new QGridLayout;
config_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
config_widget->setMaximumHeight(m_configHeight);
config_widget->setLayout(config_layout);
display_splitter->addWidget(config_widget);
// Pre-compute target pixmap size based on monitor DPI.
// Using setDevicePixelRatio() on pixmap allows the SVG image to be razor
// sharp on High-DPI screens, but the desired size must be manually
// enlarged. No idea how to make Qt do it in a more reasonable way.
QSize iconSize = QSize(22.0 * devicePixelRatio(), 22.0 * devicePixelRatio());
QSize buttonSize = 1.2 * iconSize;
// pause and freeze buttons
PixmapButton *pauseButton = new PixmapButton(this, tr("Pause"));
pauseButton->setToolTip(tr("Pause data acquisition"));
QPixmap *pauseOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("play").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *pauseOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("pause").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
pauseOnPixmap->setDevicePixelRatio(devicePixelRatio());
pauseOffPixmap->setDevicePixelRatio(devicePixelRatio());
pauseButton->setActiveGraphic(*pauseOnPixmap);
pauseButton->setInactiveGraphic(*pauseOffPixmap);
pauseButton->setCheckable(true);
pauseButton->setModel(&controls->m_pauseModel);
config_layout->addWidget(pauseButton, 0, 0, 2, 1);
PixmapButton *refFreezeButton = new PixmapButton(this, tr("Reference freeze"));
refFreezeButton->setToolTip(tr("Freeze current input as a reference / disable falloff in peak-hold mode."));
QPixmap *freezeOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *freezeOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze_off").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
freezeOnPixmap->setDevicePixelRatio(devicePixelRatio());
freezeOffPixmap->setDevicePixelRatio(devicePixelRatio());
refFreezeButton->setActiveGraphic(*freezeOnPixmap);
refFreezeButton->setInactiveGraphic(*freezeOffPixmap);
refFreezeButton->setCheckable(true);
refFreezeButton->setModel(&controls->m_refFreezeModel);
config_layout->addWidget(refFreezeButton, 2, 0, 2, 1);
// misc configuration switches
LedCheckBox *waterfallButton = new LedCheckBox(tr("Waterfall"), this);
waterfallButton->setToolTip(tr("Display real-time spectrogram"));
waterfallButton->setCheckable(true);
waterfallButton->setMinimumSize(70, 12);
waterfallButton->setModel(&controls->m_waterfallModel);
config_layout->addWidget(waterfallButton, 0, 1);
LedCheckBox *smoothButton = new LedCheckBox(tr("Averaging"), this);
smoothButton->setToolTip(tr("Enable exponential moving average"));
smoothButton->setCheckable(true);
smoothButton->setMinimumSize(70, 12);
smoothButton->setModel(&controls->m_smoothModel);
config_layout->addWidget(smoothButton, 1, 1);
LedCheckBox *stereoButton = new LedCheckBox(tr("Stereo"), this);
stereoButton->setToolTip(tr("Display stereo channels separately"));
stereoButton->setCheckable(true);
stereoButton->setMinimumSize(70, 12);
stereoButton->setModel(&controls->m_stereoModel);
config_layout->addWidget(stereoButton, 2, 1);
LedCheckBox *peakHoldButton = new LedCheckBox(tr("Peak hold"), this);
peakHoldButton->setToolTip(tr("Display envelope of peak values"));
peakHoldButton->setCheckable(true);
peakHoldButton->setMinimumSize(70, 12);
peakHoldButton->setModel(&controls->m_peakHoldModel);
config_layout->addWidget(peakHoldButton, 3, 1);
// frequency: linear / log. switch and range selector
PixmapButton *logXButton = new PixmapButton(this, tr("Logarithmic frequency"));
logXButton->setToolTip(tr("Switch between logarithmic and linear frequency scale"));
QPixmap *logXOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *logXOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
logXOnPixmap->setDevicePixelRatio(devicePixelRatio());
logXOffPixmap->setDevicePixelRatio(devicePixelRatio());
logXButton->setActiveGraphic(*logXOnPixmap);
logXButton->setInactiveGraphic(*logXOffPixmap);
logXButton->setCheckable(true);
logXButton->setModel(&controls->m_logXModel);
config_layout->addWidget(logXButton, 0, 2, 2, 1, Qt::AlignRight);
ComboBox *freqRangeCombo = new ComboBox(this, tr("Frequency range"));
freqRangeCombo->setToolTip(tr("Frequency range"));
freqRangeCombo->setMinimumSize(100, 22);
freqRangeCombo->setMaximumSize(200, 22);
freqRangeCombo->setModel(&controls->m_freqRangeModel);
config_layout->addWidget(freqRangeCombo, 0, 3, 2, 1);
// amplitude: linear / log switch and range selector
PixmapButton *logYButton = new PixmapButton(this, tr("Logarithmic amplitude"));
logYButton->setToolTip(tr("Switch between logarithmic and linear amplitude scale"));
QPixmap *logYOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QPixmap *logYOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
logYOnPixmap->setDevicePixelRatio(devicePixelRatio());
logYOffPixmap->setDevicePixelRatio(devicePixelRatio());
logYButton->setActiveGraphic(*logYOnPixmap);
logYButton->setInactiveGraphic(*logYOffPixmap);
logYButton->setCheckable(true);
logYButton->setModel(&controls->m_logYModel);
config_layout->addWidget(logYButton, 2, 2, 2, 1, Qt::AlignRight);
ComboBox *ampRangeCombo = new ComboBox(this, tr("Amplitude range"));
ampRangeCombo->setToolTip(tr("Amplitude range"));
ampRangeCombo->setMinimumSize(100, 22);
ampRangeCombo->setMaximumSize(200, 22);
ampRangeCombo->setModel(&controls->m_ampRangeModel);
config_layout->addWidget(ampRangeCombo, 2, 3, 2, 1);
// FFT: block size: icon and selector
QLabel *blockSizeLabel = new QLabel("", this);
QPixmap *blockSizeIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("block_size"));
blockSizeIcon->setDevicePixelRatio(devicePixelRatio());
blockSizeLabel->setPixmap(blockSizeIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
config_layout->addWidget(blockSizeLabel, 0, 4, 2, 1, Qt::AlignRight);
ComboBox *blockSizeCombo = new ComboBox(this, tr("FFT block bize"));
blockSizeCombo->setToolTip(tr("FFT block size"));
blockSizeCombo->setMinimumSize(100, 22);
blockSizeCombo->setMaximumSize(200, 22);
blockSizeCombo->setModel(&controls->m_blockSizeModel);
config_layout->addWidget(blockSizeCombo, 0, 5, 2, 1);
processor->reallocateBuffers();
connect(&controls->m_blockSizeModel, &ComboBoxModel::dataChanged, [=] {processor->reallocateBuffers();});
// FFT: window type: icon and selector
QLabel *windowLabel = new QLabel("", this);
QPixmap *windowIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("window"));
windowIcon->setDevicePixelRatio(devicePixelRatio());
windowLabel->setPixmap(windowIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
config_layout->addWidget(windowLabel, 2, 4, 2, 1, Qt::AlignRight);
ComboBox *windowCombo = new ComboBox(this, tr("FFT window type"));
windowCombo->setToolTip(tr("FFT window type"));
windowCombo->setMinimumSize(100, 22);
windowCombo->setMaximumSize(200, 22);
windowCombo->setModel(&controls->m_windowModel);
config_layout->addWidget(windowCombo, 2, 5, 2, 1);
processor->rebuildWindow();
connect(&controls->m_windowModel, &ComboBoxModel::dataChanged, [=] {processor->rebuildWindow();});
// QSplitter middle and bottom: spectrum display widgets
m_spectrum = new SaSpectrumView(controls, processor, this);
display_splitter->addWidget(m_spectrum);
m_waterfall = new SaWaterfallView(controls, processor, this);
display_splitter->addWidget(m_waterfall);
m_waterfall->setVisible(m_controls->m_waterfallModel.value());
connect(&controls->m_waterfallModel, &BoolModel::dataChanged, [=] {m_waterfall->updateVisibility();});
}
// Suggest the best current widget size.
QSize SaControlsDialog::sizeHint() const
{
// Best width is determined by spectrum display sizeHint.
// Best height depends on whether waterfall is visible and
// consists of heights of the config section, spectrum, waterfall
// and some reserve for margins.
if (m_waterfall->isVisible())
{
return QSize(m_spectrum->sizeHint().width(),
m_configHeight + m_spectrum->sizeHint().height() + m_waterfall->sizeHint().height() + 50);
}
else
{
return QSize(m_spectrum->sizeHint().width(),
m_configHeight + m_spectrum->sizeHint().height() + 50);
}
}

View File

@@ -0,0 +1,57 @@
/*
* SaControlsDialog.h - declatation of SaControlsDialog class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SACONTROLSDIALOG_H
#define SACONTROLSDIALOG_H
#include "EffectControlDialog.h"
#include "SaControls.h"
#include "SaSpectrumView.h"
#include "SaProcessor.h"
#include "SaWaterfallView.h"
//! Top-level widget holding the configuration GUI and spectrum displays
class SaControlsDialog : public EffectControlDialog
{
Q_OBJECT
public:
explicit SaControlsDialog(SaControls *controls, SaProcessor *processor);
virtual ~SaControlsDialog() {}
bool isResizable() const override {return true;}
QSize sizeHint() const override;
private:
SaControls *m_controls;
SaProcessor *m_processor;
// Pointers to created widgets are needed to keep track of their sizeHint() changes.
// Config widget is a plain QWidget so it has just a fixed height instead.
const int m_configHeight = 75;
SaSpectrumView *m_spectrum;
SaWaterfallView *m_waterfall;
};
#endif // SACONTROLSDIALOG_H

View File

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

View File

@@ -0,0 +1,122 @@
/* SaProcessor.h - declaration of SaProcessor class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SAPROCESSOR_H
#define SAPROCESSOR_H
#include <QColor>
#include <QMutex>
#include <vector>
#include "fft_helpers.h"
#include "SaControls.h"
//! Receives audio data, runs FFT analysis and stores the result.
class SaProcessor
{
public:
explicit SaProcessor(SaControls *controls);
virtual ~SaProcessor();
void analyse(sampleFrame *in_buffer, const fpp_t frame_count);
// inform processor if any processing is actually required
void setSpectrumActive(bool active);
void setWaterfallActive(bool active);
// configuration is taken from models in SaControls; some changes require
// an exlicit update request (reallocation and window rebuild)
void reallocateBuffers();
void rebuildWindow();
void clear();
// information about results and unit conversion helpers
float binToFreq(unsigned int bin_index) const;
float binBandwidth() const;
float freqToXPixel(float frequency, unsigned int width) const;
float xPixelToFreq(float x, unsigned int width) const;
float ampToYPixel(float amplitude, unsigned int height) const;
float yPixelToAmp(float y, unsigned int height) const;
unsigned int getSampleRate() const;
float getNyquistFreq() const;
float getFreqRangeMin(bool linear = false) const;
float getFreqRangeMax() const;
float getAmpRangeMin(bool linear = false) const;
float getAmpRangeMax() const;
// data access lock must be acquired by any friendly class that touches
// the results, mainly to prevent unexpected mid-way reallocation
QMutex m_dataAccess;
private:
SaControls *m_controls;
// currently valid configuration
const unsigned int m_zeroPadFactor = 2; //!< use n-steps bigger FFT for given block size
unsigned int m_inBlockSize; //!< size of input (time domain) data block
unsigned int m_fftBlockSize; //!< size of padded block for FFT processing
unsigned int m_sampleRate;
unsigned int binCount() const; //!< size of output (frequency domain) data block
// data buffers (roughly in the order of processing, from input to output)
unsigned int m_framesFilledUp;
std::vector<float> m_bufferL; //!< time domain samples (left)
std::vector<float> m_bufferR; //!< time domain samples (right)
std::vector<float> m_fftWindow; //!< precomputed window function coefficients
fftwf_plan m_fftPlanL;
fftwf_plan m_fftPlanR;
fftwf_complex *m_spectrumL; //!< frequency domain samples (complex) (left)
fftwf_complex *m_spectrumR; //!< frequency domain samples (complex) (right)
std::vector<float> m_absSpectrumL; //!< frequency domain samples (absolute) (left)
std::vector<float> m_absSpectrumR; //!< frequency domain samples (absolute) (right)
std::vector<float> m_normSpectrumL; //!< frequency domain samples (normalized) (left)
std::vector<float> m_normSpectrumR; //!< frequency domain samples (normalized) (right)
// spectrum history for waterfall: new normSpectrum lines are added on top
std::vector<uchar> m_history;
const unsigned int m_waterfallHeight = 200; // Number of stored lines.
// Note: high values may make it harder to see transients.
// book keeping
bool m_spectrumActive;
bool m_waterfallActive;
unsigned int m_waterfallNotEmpty;
bool m_reallocating;
// merge L and R channels and apply gamma correction to make a spectrogram pixel
QRgb makePixel(float left, float right, float gamma_correction = 0.30) const;
friend class SaSpectrumView;
friend class SaWaterfallView;
};
#endif // SAPROCESSOR_H

View File

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

View File

@@ -0,0 +1,126 @@
/* SaSpectrumView.h - declaration of SaSpectrumView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* Based partially on Eq plugin code,
* Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SASPECTRUMVIEW_H
#define SASPECTRUMVIEW_H
#include <string>
#include <utility>
#include <QPainterPath>
#include <QWidget>
class QMouseEvent;
class QPainter;
class SaControls;
class SaProcessor;
//! Widget that displays a spectrum curve and frequency / amplitude grid
class SaSpectrumView : public QWidget
{
Q_OBJECT
public:
explicit SaSpectrumView(SaControls *controls, SaProcessor *processor, QWidget *_parent = 0);
virtual ~SaSpectrumView() {}
QSize sizeHint() const override {return QSize(400, 200);}
protected:
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private slots:
void periodicUpdate();
private:
const SaControls *m_controls;
SaProcessor *m_processor;
// grid labels (position, label) and methods to generate them
std::vector<std::pair<int, std::string>> m_logFreqTics; // 10-20-50... Hz
std::vector<std::pair<int, std::string>> m_linearFreqTics; // 2k-4k-6k... Hz
std::vector<std::pair<float, std::string>> m_logAmpTics; // dB
std::vector<std::pair<float, std::string>> m_linearAmpTics; // 0..1
std::vector<std::pair<int, std::string>> makeLogFreqTics(int low, int high);
std::vector<std::pair<int, std::string>> makeLinearFreqTics(int low, int high);
std::vector<std::pair<float, std::string>> makeLogAmpTics(int low, int high);
std::vector<std::pair<float, std::string>> makeLinearAmpTics(int low, int high);
// currently selected ranges (see SaControls.h for enum definitions)
int m_freqRangeIndex;
int m_ampRangeIndex;
// draw the grid and all labels based on selected ranges
void drawGrid(QPainter &painter);
// local buffers for frequency bin values and a method to update them
// (mainly needed for averaging and to keep track of peak values)
std::vector<float> m_displayBufferL;
std::vector<float> m_displayBufferR;
std::vector<float> m_peakBufferL;
std::vector<float> m_peakBufferR;
void updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer);
// final paths to be drawn by QPainter and methods to build them
QPainterPath m_pathL;
QPainterPath m_pathR;
QPainterPath m_pathPeakL;
QPainterPath m_pathPeakR;
void refreshPaths();
QPainterPath makePath(std::vector<float> &displayBuffer, float resolution);
// helper variables for path drawing
float m_decaySum; // indicates if there is anything left to draw
bool m_freezeRequest; // new reference should be acquired
bool m_frozen; // a reference is currently stored in the peakBuffer
const float m_smoothFactor = 0.15; // alpha for exponential smoothing
const float m_peakDecayFactor = 0.992; // multiplier for gradual peak decay
// top level: refresh buffers, make paths and draw the spectrum
void drawSpectrum(QPainter &painter);
// current cursor location and a method to draw it
QPoint m_cursor;
void drawCursor(QPainter &painter);
// wrappers for most used SaProcessor conversion helpers
// (to make local code more readable)
float binToFreq(unsigned int bin_index);
float freqToXPixel(float frequency, unsigned int width);
float ampToYPixel(float amplitude, unsigned int height);
// current boundaries for drawing
unsigned int m_displayTop;
unsigned int m_displayBottom;
unsigned int m_displayLeft;
unsigned int m_displayRight;
unsigned int m_displayWidth;
};
#endif // SASPECTRUMVIEW_H

View File

@@ -0,0 +1,230 @@
/* SaWaterfallViewView.cpp - implementation of SaWaterfallViewView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SaWaterfallView.h"
#include <algorithm>
#include <cmath>
#include <QImage>
#include <QMutexLocker>
#include <QPainter>
#include <QSplitter>
#include <QString>
#include "EffectControlDialog.h"
#include "GuiApplication.h"
#include "MainWindow.h"
#include "SaProcessor.h"
SaWaterfallView::SaWaterfallView(SaControls *controls, SaProcessor *processor, QWidget *_parent) :
QWidget(_parent),
m_controls(controls),
m_processor(processor)
{
m_controlDialog = (EffectControlDialog*) _parent;
setMinimumSize(300, 150);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(gui->mainWindow(), SIGNAL(periodicUpdate()), this, SLOT(periodicUpdate()));
m_timeTics = makeTimeTics();
m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate();
}
// Compose and draw all the content; called by Qt.
// Not as performance sensitive as SaSpectrumView, most of the processing is
// done directly in SaProcessor.
void SaWaterfallView::paintEvent(QPaintEvent *event)
{
#ifdef SA_DEBUG
int start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
// all drawing done here, local variables are sufficient for the boundary
const int displayTop = 1;
const int displayBottom = height() -2;
const int displayLeft = 26;
const int displayRight = width() -26;
const int displayWidth = displayRight - displayLeft;
float label_width = 20;
float label_height = 16;
float margin = 2;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
// check if time labels need to be rebuilt
if ((float)m_processor->m_inBlockSize / m_processor->getSampleRate() != m_oldTimePerLine)
{
m_timeTics = makeTimeTics();
m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate();
}
// print time labels
float pos = 0;
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
for (auto & line: m_timeTics)
{
pos = timeToYPixel(line.first, displayBottom);
// align first and last label to the edge if needed, otherwise center them
if (line == m_timeTics.front() && pos < label_height / 2)
{
painter.drawText(displayLeft - label_width - margin, displayTop - 1,
label_width, label_height, Qt::AlignRight | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, displayTop - 1,
label_width, label_height, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip,
QString(line.second.c_str()));
}
else if (line == m_timeTics.back() && pos > displayBottom - label_height + 2)
{
painter.drawText(displayLeft - label_width - margin, displayBottom - label_height,
label_width, label_height, Qt::AlignRight | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, displayBottom - label_height + 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignBottom | Qt::TextDontClip,
QString(line.second.c_str()));
}
else
{
painter.drawText(displayLeft - label_width - margin, pos - label_height / 2,
label_width, label_height, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
painter.drawText(displayRight + margin, pos - label_height / 2,
label_width, label_height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip,
QString(line.second.c_str()));
}
}
// draw the spectrogram precomputed in SaProcessor
if (m_processor->m_waterfallNotEmpty)
{
QMutexLocker lock(&m_processor->m_dataAccess);
painter.drawImage(displayLeft, displayTop, // top left corner coordinates
QImage(m_processor->m_history.data(), // raw pixel data to display
m_processor->binCount(), // width = number of frequency bins
m_processor->m_waterfallHeight, // height = number of history lines
QImage::Format_RGB32
).scaled(displayWidth, // scale to fit view..
displayBottom,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
lock.unlock();
}
else
{
painter.fillRect(displayLeft, displayTop, displayWidth, displayBottom, QColor(0,0,0));
}
// always draw the outline
painter.setPen(QPen(m_controls->m_colorGrid, 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawRoundedRect(displayLeft, displayTop, displayWidth, displayBottom, 2.0, 2.0);
#ifdef SA_DEBUG
// display what FPS would be achieved if waterfall ran in a loop
start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - start_time;
painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
painter.drawText(displayRight -100, 10, 100, 16, Qt::AlignLeft,
QString(std::string("Max FPS: " + std::to_string(1000000000.0 / start_time)).c_str()));
#endif
}
// Convert time value to Y coordinate for display of given height.
float SaWaterfallView::timeToYPixel(float time, int height)
{
float pixels_per_line = (float)height / m_processor->m_waterfallHeight;
float seconds_per_line = ((float)m_processor->m_inBlockSize / m_processor->getSampleRate());
return pixels_per_line * time / seconds_per_line;
}
// Generate labels for linear time scale.
std::vector<std::pair<float, std::string>> SaWaterfallView::makeTimeTics()
{
std::vector<std::pair<float, std::string>> result;
float i;
// upper limit defined by number of lines * time per line
float limit = m_processor->m_waterfallHeight * ((float)m_processor->m_inBlockSize / m_processor->getSampleRate());
// set increment so that about 8 tics are generated
float increment = std::round(10 * limit / 7) / 10;
// NOTE: labels positions are rounded to match the (rounded) label value
for (i = 0; i <= limit; i += increment)
{
if (i < 10)
{
result.emplace_back(std::round(i * 10) / 10, std::to_string(std::round(i * 10) / 10).substr(0, 3));
}
else
{
result.emplace_back(std::round(i), std::to_string(std::round(i)).substr(0, 2));
}
}
return result;
}
// Periodically trigger repaint and check if the widget is visible.
// If it is not, stop drawing and inform the processor.
void SaWaterfallView::periodicUpdate()
{
m_processor->setWaterfallActive(isVisible());
if (isVisible()) {update();}
}
// Adjust window size and widget visibility when waterfall is enabled or disabbled.
void SaWaterfallView::updateVisibility()
{
// get container of the control dialog to be resized if needed
QWidget *subWindow = m_controlDialog->parentWidget();
if (m_controls->m_waterfallModel.value())
{
// clear old data before showing the waterfall
QMutexLocker lock(&m_processor->m_dataAccess);
std::fill(m_processor->m_history.begin(), m_processor->m_history.end(), 0);
lock.unlock();
setVisible(true);
// increase window size if it is too small
if (subWindow->size().height() < m_controlDialog->sizeHint().height())
{
subWindow->resize(subWindow->size().width(), m_controlDialog->sizeHint().height());
}
}
else
{
setVisible(false);
// decrease window size only if it does not violate sizeHint
subWindow->resize(subWindow->size().width(), m_controlDialog->sizeHint().height());
}
}

View File

@@ -0,0 +1,66 @@
/* SaWaterfallView.h - declaration of SaWaterfallView class.
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SAWATERFALLVIEW_H
#define SAWATERFALLVIEW_H
#include <string>
#include <utility>
#include <vector>
#include <QPainter>
#include <QWidget>
#include "SaControls.h"
#include "SaProcessor.h"
// Widget that displays a spectrum waterfall (spectrogram) and time labels.
class SaWaterfallView : public QWidget
{
Q_OBJECT
public:
explicit SaWaterfallView(SaControls *controls, SaProcessor *processor, QWidget *_parent = 0);
virtual ~SaWaterfallView() {}
QSize sizeHint() const override {return QSize(400, 350);}
// Check if waterfall should be displayed and adjust window size if needed.
void updateVisibility();
protected:
void paintEvent(QPaintEvent *event) override;
private slots:
void periodicUpdate();
private:
const SaControls *m_controls;
SaProcessor *m_processor;
const EffectControlDialog *m_controlDialog;
// Methods and data used to make time labels
float m_oldTimePerLine;
float timeToYPixel(float time, int height);
std::vector<std::pair<float, std::string>> makeTimeTics();
std::vector<std::pair<float, std::string>> m_timeTics; // 0..n (s)
};
#endif // SAWATERFALLVIEW_H

View File

@@ -1,172 +0,0 @@
/*
* SpectrumAnalyzer.cpp - spectrum analyzer effect plugin
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SpectrumAnalyzer.h"
#include "embed.h"
extern "C"
{
Plugin::Descriptor PLUGIN_EXPORT spectrumanalyzer_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"Spectrum Analyzer",
QT_TRANSLATE_NOOP( "pluginBrowser", "Graphical spectrum analyzer plugin" ),
"Tobias Doerffel <tobydox/at/users.sf.net>",
0x0100,
Plugin::Effect,
new PluginPixmapLoader(),
NULL,
NULL
} ;
}
SpectrumAnalyzer::SpectrumAnalyzer( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key ) :
Effect( &spectrumanalyzer_plugin_descriptor, _parent, _key ),
m_saControls( this ),
m_framesFilledUp( 0 ),
m_energy( 0 )
{
memset( m_buffer, 0, sizeof( m_buffer ) );
m_specBuf = (fftwf_complex *) fftwf_malloc( ( FFT_BUFFER_SIZE + 1 ) * sizeof( fftwf_complex ) );
m_fftPlan = fftwf_plan_dft_r2c_1d( FFT_BUFFER_SIZE*2, m_buffer, m_specBuf, FFTW_MEASURE );
}
SpectrumAnalyzer::~SpectrumAnalyzer()
{
fftwf_destroy_plan( m_fftPlan );
fftwf_free( m_specBuf );
}
bool SpectrumAnalyzer::processAudioBuffer( sampleFrame* _buf, const fpp_t _frames )
{
if( !isEnabled() || !isRunning () )
{
return false;
}
if( !m_saControls.isViewVisible() )
{
return true;
}
fpp_t f = 0;
if( _frames > FFT_BUFFER_SIZE )
{
m_framesFilledUp = 0;
f = _frames - FFT_BUFFER_SIZE;
}
const int cm = m_saControls.m_channelMode.value();
switch( cm )
{
case MergeChannels:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] =
( _buf[f][0] + _buf[f][1] ) * 0.5;
++m_framesFilledUp;
}
break;
case LeftChannel:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] = _buf[f][0];
++m_framesFilledUp;
}
break;
case RightChannel:
for( ; f < _frames; ++f )
{
m_buffer[m_framesFilledUp] = _buf[f][1];
++m_framesFilledUp;
}
break;
}
if( m_framesFilledUp < FFT_BUFFER_SIZE )
{
return isRunning();
}
// hanming( m_buffer, FFT_BUFFER_SIZE, HAMMING );
const sample_rate_t sr = Engine::mixer()->processingSampleRate();
const int LOWEST_FREQ = 0;
const int HIGHEST_FREQ = sr / 2;
fftwf_execute( m_fftPlan );
absspec( m_specBuf, m_absSpecBuf, FFT_BUFFER_SIZE+1 );
if( m_saControls.m_linearSpec.value() )
{
compressbands( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1,
MAX_BANDS,
(int)(LOWEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2)),
(int)(HIGHEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2)));
m_energy = maximum( m_bands, MAX_BANDS ) / maximum( m_buffer, FFT_BUFFER_SIZE );
}
else
{
calc13octaveband31( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1, sr/2.0 );
m_energy = signalpower( m_buffer, FFT_BUFFER_SIZE ) / maximum( m_buffer, FFT_BUFFER_SIZE );
}
m_framesFilledUp = 0;
checkGate( 1 );
return isRunning();
}
extern "C"
{
// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
return new SpectrumAnalyzer( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}
}

View File

@@ -1,78 +0,0 @@
/*
* SpectrumAnalyzer.h - spectrum anaylzer effect plugin
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef _SPECTRUM_ANALYZER_H
#define _SPECTRUM_ANALYZER_H
#include "Effect.h"
#include "fft_helpers.h"
#include "SpectrumAnalyzerControls.h"
const int MAX_BANDS = 249;
class SpectrumAnalyzer : public Effect
{
public:
enum ChannelModes
{
MergeChannels,
LeftChannel,
RightChannel
} ;
SpectrumAnalyzer( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key );
virtual ~SpectrumAnalyzer();
virtual bool processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames );
virtual EffectControls * controls()
{
return( &m_saControls );
}
private:
SpectrumAnalyzerControls m_saControls;
fftwf_plan m_fftPlan;
fftwf_complex * m_specBuf;
float m_absSpecBuf[FFT_BUFFER_SIZE+1];
float m_buffer[FFT_BUFFER_SIZE*2];
int m_framesFilledUp;
float m_bands[MAX_BANDS];
float m_energy;
friend class SpectrumAnalyzerControls;
friend class SpectrumView;
} ;
#endif

View File

@@ -1,194 +0,0 @@
/*
* SpectrumAnalyzerControlDialog.cpp - view for spectrum analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <cmath>
#include <QLayout>
#include <QPainter>
#include "SpectrumAnalyzer.h"
#include "MainWindow.h"
#include "GuiApplication.h"
#include "LedCheckbox.h"
#include "embed.h"
static inline void darken( QImage& img, int x, int y, int w, int h )
{
int imgWidth = img.width();
QRgb * base = ( (QRgb *) img.bits() ) + y*imgWidth + x;
for( int y = 0; y < h; ++y )
{
QRgb * d = base + y*imgWidth;
for( int x = 0; x < w; ++x )
{
// shift each color component by 1 bit and set alpha
// to 0xff
d[x] = ( ( d[x] >> 1 ) & 0x7f7f7f7f ) | 0xff000000;
}
}
}
class SpectrumView : public QWidget
{
public:
SpectrumView( SpectrumAnalyzer* s, QWidget * _parent ) :
QWidget( _parent ),
m_sa( s ),
m_backgroundPlain( PLUGIN_NAME::getIconPixmap( "spectrum_background_plain" ).toImage() ),
m_background( PLUGIN_NAME::getIconPixmap( "spectrum_background" ).toImage() )
{
setFixedSize( 249, 151 );
connect( gui->mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
setAttribute( Qt::WA_OpaquePaintEvent, true );
}
virtual ~SpectrumView()
{
}
virtual void paintEvent( QPaintEvent* event )
{
QPainter p( this );
QImage i = m_sa->m_saControls.m_linearSpec.value() ?
m_backgroundPlain : m_background;
const float e = m_sa->m_energy;
if( e <= 0 )
{
darken( i, 0, 0, i.width(), i.height() );
p.drawImage( 0, 0, i );
return;
}
const bool lin_y = m_sa->m_saControls.m_linearYAxis.value();
float * b = m_sa->m_bands;
const int LOWER_Y = -60; // dB
int h;
const int fh = height();
if( m_sa->m_saControls.m_linearSpec.value() )
{
if( lin_y )
{
for( int x = 0; x < MAX_BANDS; ++x, ++b )
{
h = fh * 2.0 / 3.0 * (*b / e );
if( h < 0 ) h = 0; else if( h >= fh ) continue;
darken( i, x, 0, 1, fh-h );
}
}
else
{
for( int x = 0; x < MAX_BANDS; ++x, ++b )
{
h = (int)( fh * 2.0 / 3.0 * (20*(log10( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) );
if( h < 0 ) h = 0; else if( h >= fh ) continue;
darken( i, x, 0, 1, fh-h );
}
}
}
else
{
if( lin_y )
{
for( int x = 0; x < 31; ++x, ++b )
{
h = fh * 2.0 / 3.0 * ( 1.2 * *b / e );
if( h < 0 ) h = 0; else if( h >= fh ) continue; else h = ( h / 3 ) * 3;
darken( i, x*8, 0, 8, fh-h );
}
}
else
{
for( int x = 0; x < 31; ++x, ++b )
{
h = (int)( fh * 2.0 / 3.0 * (20*(log10( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) );
if( h < 0 ) h = 0; else if( h >= fh ) continue; else h = ( h / 3 ) * 3;
darken( i, x*8, 0, 8, fh-h );
}
}
darken( i, 31*8, 0, 1, fh );
}
p.drawImage( 0, 0, i );
}
private:
SpectrumAnalyzer * m_sa;
QImage m_backgroundPlain;
QImage m_background;
} ;
SpectrumAnalyzerControlDialog::SpectrumAnalyzerControlDialog( SpectrumAnalyzerControls* controls ) :
EffectControlDialog( controls ),
m_controls( controls ),
m_logXAxis( PLUGIN_NAME::getIconPixmap( "log_x_axis" ) ),
m_logYAxis( PLUGIN_NAME::getIconPixmap( "log_y_axis" ) )
{
setAutoFillBackground( true );
QPalette pal;
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "background" ) );
setFixedSize( 293, 205 );
setPalette( pal );
/* QVBoxLayout * l = new QVBoxLayout( this );*/
SpectrumView* v = new SpectrumView( controls->m_effect, this );
v->move( 34, 10 );
LedCheckBox * lin_spec = new LedCheckBox( tr( "Linear spectrum" ), this );
lin_spec->move( 32, 182 );
lin_spec->setModel( &controls->m_linearSpec );
LedCheckBox * lin_y = new LedCheckBox( tr( "Linear Y axis" ), this );
lin_y->move( 137, 182 );
lin_y->setModel( &controls->m_linearYAxis );
connect( &controls->m_linearSpec, SIGNAL( dataChanged() ), this, SLOT( update() ) );
connect( &controls->m_linearYAxis, SIGNAL( dataChanged() ), this, SLOT( update() ) );
/* l->addWidget( v );
l->addWidget( lin_spec );
l->addWidget( lin_y );*/
}
void SpectrumAnalyzerControlDialog::paintEvent( QPaintEvent * )
{
QPainter p( this );
if( !m_controls->m_linearSpec.value() )
{
p.drawPixmap( 33, 165, m_logXAxis );
}
if( !m_controls->m_linearYAxis.value() )
{
p.drawPixmap( 10, 29, m_logYAxis);
}
}

View File

@@ -1,61 +0,0 @@
/*
* SpectrumAnalyzerControls.cpp - controls for spectrum analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SpectrumAnalyzer.h"
#include "SpectrumAnalyzerControls.h"
SpectrumAnalyzerControls::SpectrumAnalyzerControls( SpectrumAnalyzer* effect ) :
EffectControls( effect ),
m_effect( effect ),
m_linearSpec( false, this, tr( "Linear spectrum" ) ),
m_linearYAxis( false, this, tr( "Linear Y axis" ) ),
m_channelMode( SpectrumAnalyzer::MergeChannels,
SpectrumAnalyzer::MergeChannels,
SpectrumAnalyzer::RightChannel,
this, tr( "Channel mode" ) )
{
}
void SpectrumAnalyzerControls::loadSettings( const QDomElement & _this )
{
}
void SpectrumAnalyzerControls::saveSettings( QDomDocument & _doc,
QDomElement & _this )
{
}

View File

@@ -1,75 +0,0 @@
/*
* SpectrumAnalyzerControls.h - controls for spectrum-analyzer
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef SPECTRUM_ANALYZER_CONTROLS_H
#define SPECTRUM_ANALYZER_CONTROLS_H
#include "EffectControls.h"
#include "SpectrumAnalyzerControlDialog.h"
#include "Knob.h"
class SpectrumAnalyzer;
class SpectrumAnalyzerControls : public EffectControls
{
Q_OBJECT
public:
SpectrumAnalyzerControls( SpectrumAnalyzer* effect );
virtual ~SpectrumAnalyzerControls()
{
}
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
virtual void loadSettings( const QDomElement & _this );
inline virtual QString nodeName() const
{
return "spectrumanaylzercontrols";
}
virtual int controlCount()
{
return 1;
}
virtual EffectControlDialog * createView()
{
return new SpectrumAnalyzerControlDialog( this );
}
private:
SpectrumAnalyzer* m_effect;
BoolModel m_linearSpec;
BoolModel m_linearYAxis;
IntModel m_channelMode;
friend class SpectrumAnalyzer;
friend class SpectrumAnalyzerControlDialog;
friend class SpectrumView;
} ;
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 859 B

View File

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

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

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

After

Width:  |  Height:  |  Size: 10 KiB

View File

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

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

View File

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

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

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

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

View File

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

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

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

After

Width:  |  Height:  |  Size: 11 KiB

View File

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

After

Width:  |  Height:  |  Size: 11 KiB

View File

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

After

Width:  |  Height:  |  Size: 11 KiB

View File

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

After

Width:  |  Height:  |  Size: 10 KiB

View File

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

View File

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

View File

@@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 840 B

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 B

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

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

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