diff --git a/include/graph.h b/include/graph.h index 20437996e..1936da635 100644 --- a/include/graph.h +++ b/include/graph.h @@ -46,14 +46,19 @@ public: { NearestStyle, LinearStyle, + LinearNonCyclicStyle, NumGraphStyles }; - graph( QWidget * _parent, graphStyle _style = graph::LinearStyle ); + graph( QWidget * _parent, graphStyle _style = graph::LinearStyle, + int _width = 132, + int _height = 104 + ); virtual ~graph(); void setForeground( const QPixmap & _pixmap ); + void setGraphColor( const QColor ); inline graphModel * model() @@ -65,6 +70,7 @@ public: { return m_graphStyle; } + inline void setGraphStyle( graphStyle _s ) { @@ -88,7 +94,8 @@ protected slots: private: virtual void modelChanged(); - void changeSampleAt(int _x, int _y); + void changeSampleAt( int _x, int _y ); + void drawLineAt( int _x, int _y, int _lastx ); QPixmap m_foreground; @@ -154,6 +161,7 @@ public slots: QString setWaveToUser( ); void smooth(); + void smoothNonCyclic(); void normalize(); signals: diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6f315b792..01aa7868b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -25,5 +25,6 @@ ADD_SUBDIRECTORY(triple_oscillator) ADD_SUBDIRECTORY(vestige) ADD_SUBDIRECTORY(vst_base) ADD_SUBDIRECTORY(vst_effect) +ADD_SUBDIRECTORY(waveshaper) ADD_SUBDIRECTORY(vibed) ADD_SUBDIRECTORY(zynaddsubfx) diff --git a/plugins/waveshaper/CMakeLists.txt b/plugins/waveshaper/CMakeLists.txt new file mode 100644 index 000000000..f4b4bc952 --- /dev/null +++ b/plugins/waveshaper/CMakeLists.txt @@ -0,0 +1,3 @@ +INCLUDE(BuildPlugin) + +BUILD_PLUGIN(waveshaper waveshaper.cpp waveshaper_controls.cpp waveshaper_control_dialog.cpp MOCFILES waveshaper_controls.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") diff --git a/plugins/waveshaper/artwork.png b/plugins/waveshaper/artwork.png new file mode 100644 index 000000000..fac96bcb4 Binary files /dev/null and b/plugins/waveshaper/artwork.png differ diff --git a/plugins/waveshaper/logo.png b/plugins/waveshaper/logo.png new file mode 100644 index 000000000..89e9f3680 Binary files /dev/null and b/plugins/waveshaper/logo.png differ diff --git a/plugins/waveshaper/reset_active.png b/plugins/waveshaper/reset_active.png new file mode 100644 index 000000000..0f4c8b9a6 Binary files /dev/null and b/plugins/waveshaper/reset_active.png differ diff --git a/plugins/waveshaper/reset_inactive.png b/plugins/waveshaper/reset_inactive.png new file mode 100644 index 000000000..57c0a7a85 Binary files /dev/null and b/plugins/waveshaper/reset_inactive.png differ diff --git a/plugins/waveshaper/smooth_active.png b/plugins/waveshaper/smooth_active.png new file mode 100644 index 000000000..62cba64b5 Binary files /dev/null and b/plugins/waveshaper/smooth_active.png differ diff --git a/plugins/waveshaper/smooth_inactive.png b/plugins/waveshaper/smooth_inactive.png new file mode 100644 index 000000000..53bddbb83 Binary files /dev/null and b/plugins/waveshaper/smooth_inactive.png differ diff --git a/plugins/waveshaper/wavegraph.png b/plugins/waveshaper/wavegraph.png new file mode 100644 index 000000000..eb3efa968 Binary files /dev/null and b/plugins/waveshaper/wavegraph.png differ diff --git a/plugins/waveshaper/waveshaper.cpp b/plugins/waveshaper/waveshaper.cpp new file mode 100644 index 000000000..a7c1f037d --- /dev/null +++ b/plugins/waveshaper/waveshaper.cpp @@ -0,0 +1,154 @@ +/* + * waveshaper.cpp - waveshaper effect-plugin + * + * * Copyright * (c) 2014 Vesa Kivimäki + * Copyright (c) 2006-2009 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 "waveshaper.h" +#include +#include "embed.cpp" + + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT waveshaper_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Waveshaper Effect", + QT_TRANSLATE_NOOP( "pluginBrowser", + "plugin for waveshaping" ), + "Vesa Kivimäki ", + 0x0100, + Plugin::Effect, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + +} + + + +waveShaperEffect::waveShaperEffect( Model * _parent, + const Descriptor::SubPluginFeatures::Key * _key ) : + Effect( &waveshaper_plugin_descriptor, _parent, _key ), + m_wsControls( this ) +{ +} + + + + +waveShaperEffect::~waveShaperEffect() +{ +} + + + + +bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf, + const fpp_t _frames ) +{ + if( !isEnabled() || !isRunning () ) + { + return( false ); + } + +// variables for effect + int i = 0; + float lookup; + float frac; + float posneg; + + double out_sum = 0.0; + const float d = dryLevel(); + const float w = wetLevel(); + for( fpp_t f = 0; f < _frames; ++f ) + { + sample_t s[2] = { _buf[f][0], _buf[f][1] }; + +// apply input gain + s[0] *= m_wsControls.m_inputModel.value(); + s[1] *= m_wsControls.m_inputModel.value(); + +// start effect + + for ( i=0; i <= 1; ++i ) + { + lookup = fabsf( s[i] ) * 200.0f; + posneg = s[i] < 0 ? -1.0f : 1.0f; + + if ( lookup < 1 ) + { + frac = lookup - truncf(lookup); + s[i] = frac * m_wsControls.m_wavegraphModel.samples()[0] * posneg; + } + else + if ( lookup < 200 ) + { + frac = lookup - truncf(lookup); + s[i] = + (( (1.0f-frac) * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) - 1 ] ) + + ( frac * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) ] )) + * posneg; + } + else + { + s[i] *= m_wsControls.m_wavegraphModel.samples()[199]; + } + } + +// apply output gain + s[0] *= m_wsControls.m_outputModel.value(); + s[1] *= m_wsControls.m_outputModel.value(); + +// mix wet/dry signals + _buf[f][0] = d * _buf[f][0] + w * s[0]; + _buf[f][1] = d * _buf[f][1] + w * s[1]; + + out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1]; + } + + checkGate( out_sum / _frames ); + + return( isRunning() ); +} + + + + + +extern "C" +{ + +// necessary for getting instance out of shared lib +Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data ) +{ + return( new waveShaperEffect( _parent, + static_cast( + _data ) ) ); +} + +} + diff --git a/plugins/waveshaper/waveshaper.h b/plugins/waveshaper/waveshaper.h new file mode 100644 index 000000000..016cab4de --- /dev/null +++ b/plugins/waveshaper/waveshaper.h @@ -0,0 +1,63 @@ +/* + * waveshaper.h - bass-booster-effect-plugin + * + * * Copyright * (c) 2014 Vesa Kivimäki + * Copyright (c) 2006-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 _WAVESHAPER_H +#define _WAVESHAPER_H + +#include "Effect.h" +#include "effect_lib.h" +#include "waveshaper_controls.h" + + + +class waveShaperEffect : public Effect +{ +public: + waveShaperEffect( Model * _parent, + const Descriptor::SubPluginFeatures::Key * _key ); + virtual ~waveShaperEffect(); + virtual bool processAudioBuffer( sampleFrame * _buf, + const fpp_t _frames ); + + virtual EffectControls * controls() + { + return( &m_wsControls ); + } + + +private: + + waveShaperControls m_wsControls; + + friend class waveShaperControls; + +} ; + + + + + +#endif diff --git a/plugins/waveshaper/waveshaper_control_dialog.cpp b/plugins/waveshaper/waveshaper_control_dialog.cpp new file mode 100644 index 000000000..dac97bfa0 --- /dev/null +++ b/plugins/waveshaper/waveshaper_control_dialog.cpp @@ -0,0 +1,89 @@ +/* + * waveshaper_control_dialog.cpp - control-dialog for waveshaper-effect + * + * Copyright * (c) 2014 Vesa Kivimäki + * Copyright * (c) 2006-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 + +#include "waveshaper_control_dialog.h" +#include "waveshaper_controls.h" +#include "embed.h" +#include "graph.h" +#include "pixmap_button.h" +#include "tooltip.h" + + +waveShaperControlDialog::waveShaperControlDialog( + waveShaperControls * _controls ) : + EffectControlDialog( _controls ) +{ + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), + PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + setFixedSize( 224, 300 ); + + graph * waveGraph = new graph( this, graph::LinearNonCyclicStyle, 204, 204 ); + waveGraph -> move( 10, 32 ); + waveGraph -> setModel( &_controls -> m_wavegraphModel ); + waveGraph -> setAutoFillBackground( true ); + pal = QPalette(); + pal.setBrush( backgroundRole(), + PLUGIN_NAME::getIconPixmap("wavegraph") ); + waveGraph->setPalette( pal ); + waveGraph->setGraphColor( QColor( 170, 255, 255 ) ); + waveGraph -> setMaximumSize( 204, 204 ); + + knob * inputKnob = new knob( knobBright_26, this); + inputKnob -> move( 14, 251 ); + inputKnob->setModel( &_controls->m_inputModel ); + inputKnob->setLabel( tr( "INPUT" ) ); + inputKnob->setHintText( tr( "Input gain:" ) + " ", "" ); + + knob * outputKnob = new knob( knobBright_26, this ); + outputKnob -> move( 54, 251 ); + outputKnob->setModel( &_controls->m_outputModel ); + outputKnob->setLabel( tr( "OUTPUT" ) ); + outputKnob->setHintText( tr( "Output gain:" ) + " ", "" ); + + pixmapButton * resetButton = new pixmapButton( this, tr("Reset waveform") ); + resetButton -> move( 164, 251 ); + resetButton -> resize( 12, 48 ); + resetButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "reset_active" ) ); + resetButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "reset_inactive" ) ); + toolTip::add( resetButton, tr( "Click here to reset the wavegraph back to default" ) ); + + pixmapButton * smoothButton = new pixmapButton( this, tr("Smooth waveform") ); + smoothButton -> move( 164, 267 ); + smoothButton -> resize( 12, 48 ); + smoothButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "smooth_active" ) ); + smoothButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "smooth_inactive" ) ); + toolTip::add( smoothButton, tr( "Click here to apply smooth to wavegraph" ) ); + + connect( resetButton, SIGNAL (clicked () ), + _controls, SLOT ( resetClicked() ) ); + connect( smoothButton, SIGNAL (clicked () ), + _controls, SLOT ( smoothClicked() ) ); +} diff --git a/plugins/waveshaper/waveshaper_control_dialog.h b/plugins/waveshaper/waveshaper_control_dialog.h new file mode 100644 index 000000000..d028ed04e --- /dev/null +++ b/plugins/waveshaper/waveshaper_control_dialog.h @@ -0,0 +1,48 @@ +/* + * waveshaper_control_dialog.h - control-dialog for waveshaper-effect + * + * * Copyright * (c) 2014 Vesa Kivimäki + * Copyright (c) 2006-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 _WAVESHAPER_CONTROL_DIALOG_H +#define _WAVESHAPER_CONTROL_DIALOG_H + +#include "EffectControlDialog.h" + + +class waveShaperControls; + + +class waveShaperControlDialog : public EffectControlDialog +{ +public: + waveShaperControlDialog( waveShaperControls * _controls ); + virtual ~waveShaperControlDialog() + { + } + + +private: + +} ; + +#endif diff --git a/plugins/waveshaper/waveshaper_controls.cpp b/plugins/waveshaper/waveshaper_controls.cpp new file mode 100644 index 000000000..1af27fe66 --- /dev/null +++ b/plugins/waveshaper/waveshaper_controls.cpp @@ -0,0 +1,144 @@ +/* + * waveshaper_controls.cpp - controls for waveshaper-effect + * + * Copyright * (c) 2014 Vesa Kivimäki + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 + +#include "waveshaper_controls.h" +#include "waveshaper.h" +#include "graph.h" +#include "engine.h" +#include "song.h" + + +waveShaperControls::waveShaperControls( waveShaperEffect * _eff ) : + EffectControls( _eff ), + m_effect( _eff ), + m_inputModel( 1.0f, 0.0f, 5.0f, 0.01f, this, tr( "Input gain" ) ), + m_outputModel( 1.0f, 0.0f, 5.0f, 0.01f, this, tr( "Output gain" ) ), + m_wavegraphModel( 0.0f, 1.0f, 200, this ) +{ + connect( &m_inputModel, SIGNAL( dataChanged() ), + this, SLOT( changeInput() ) ); + + connect( &m_outputModel, SIGNAL( dataChanged() ), + this, SLOT( changeOutput() ) ); + + connect( &m_wavegraphModel, SIGNAL( samplesChanged( int, int ) ), + this, SLOT( samplesChanged( int, int ) ) ); + + changeInput(); + changeOutput(); + setDefaultShape(); + +} + + + + +void waveShaperControls::changeInput() +{ +} + + + + +void waveShaperControls::changeOutput() +{ +} + + + + +void waveShaperControls::samplesChanged( int _begin, int _end) +{ +} + + + + +void waveShaperControls::loadSettings( const QDomElement & _this ) +{ +//load input, output knobs + m_inputModel.setValue( _this.attribute( "inputGain" ).toFloat() ); + m_outputModel.setValue( _this.attribute( "outputGain" ).toFloat() ); + +//load waveshape + int size = 0; + char * dst = 0; + base64::decode( _this.attribute( "waveShape"), &dst, &size ); + + m_wavegraphModel.setSamples( (float*) dst ); + delete[] dst; + +} + + + + +void waveShaperControls::saveSettings( QDomDocument & _doc, + QDomElement & _this ) +{ +//save input, output knobs + _this.setAttribute( "inputGain", m_inputModel.value() ); + _this.setAttribute( "outputGain", m_outputModel.value() ); + +//save waveshape + QString sampleString; + base64::encode( (const char *)m_wavegraphModel.samples(), + m_wavegraphModel.length() * sizeof(float), sampleString ); + _this.setAttribute( "waveShape", sampleString ); + +} + + +void waveShaperControls::setDefaultShape() +{ + float shp [200] = { }; + for ( int i = 0; i<200; i++) + { + shp[i] = ((float)i + 1.0f) / 200.0f; + } + + m_wavegraphModel.setLength( 200 ); + m_wavegraphModel.setSamples( (float*)&shp ); +} + +void waveShaperControls::resetClicked() +{ + setDefaultShape(); + engine::getSong()->setModified(); +} + +void waveShaperControls::smoothClicked() +{ + m_wavegraphModel.smoothNonCyclic(); + engine::getSong()->setModified(); +} + + + +#include "moc_waveshaper_controls.cxx" + diff --git a/plugins/waveshaper/waveshaper_controls.h b/plugins/waveshaper/waveshaper_controls.h new file mode 100644 index 000000000..a77c6a2e7 --- /dev/null +++ b/plugins/waveshaper/waveshaper_controls.h @@ -0,0 +1,85 @@ +/* + * waveshaper_controls.h - controls for waveshaper-effect + * + * Copyright * (c) 2014 Vesa Kivimäki + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 _WAVESHAPER_CONTROLS_H +#define _WAVESHAPER_CONTROLS_H + +#include "EffectControls.h" +#include "waveshaper_control_dialog.h" +#include "knob.h" +#include "graph.h" + +class waveShaperEffect; + + +class waveShaperControls : public EffectControls +{ + Q_OBJECT +public: + waveShaperControls( waveShaperEffect * _eff ); + virtual ~waveShaperControls() + { + } + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + inline virtual QString nodeName() const + { + return( "waveshapercontrols" ); + } + + virtual void setDefaultShape(); + + virtual int controlCount() + { + return( 3 ); + } + + virtual EffectControlDialog * createView() + { + return( new waveShaperControlDialog( this ) ); + } + + +private slots: + void changeInput(); + void changeOutput(); + void samplesChanged( int, int ); + + void resetClicked(); + void smoothClicked(); + +private: + waveShaperEffect * m_effect; + FloatModel m_inputModel; + FloatModel m_outputModel; + graphModel m_wavegraphModel; + + friend class waveShaperControlDialog; + friend class waveShaperEffect; + +} ; + +#endif diff --git a/plugins/zynaddsubfx/artwork.png b/plugins/zynaddsubfx/artwork.png index 7ad63c359..9a0a8d241 100644 Binary files a/plugins/zynaddsubfx/artwork.png and b/plugins/zynaddsubfx/artwork.png differ diff --git a/src/gui/piano_roll.cpp b/src/gui/piano_roll.cpp index caaf0d7d0..a545df3c0 100644 --- a/src/gui/piano_roll.cpp +++ b/src/gui/piano_roll.cpp @@ -471,7 +471,7 @@ pianoRoll::pianoRoll() : this, SLOT( zoomingChanged() ) ); m_zoomingComboBox = new comboBox( m_toolBar ); m_zoomingComboBox->setModel( &m_zoomingModel ); - m_zoomingComboBox->setFixedSize( 80, 22 ); + m_zoomingComboBox->setFixedSize( 64, 22 ); // setup quantize-stuff QLabel * quantize_lbl = new QLabel( m_toolBar ); @@ -490,7 +490,7 @@ pianoRoll::pianoRoll() : m_quantizeModel.setValue( m_quantizeModel.findText( "1/16" ) ); m_quantizeComboBox = new comboBox( m_toolBar ); m_quantizeComboBox->setModel( &m_quantizeModel ); - m_quantizeComboBox->setFixedSize( 80, 22 ); + m_quantizeComboBox->setFixedSize( 64, 22 ); connect( &m_quantizeModel, SIGNAL( dataChanged() ), this, SLOT( quantizeChanged() ) ); @@ -571,23 +571,23 @@ pianoRoll::pianoRoll() : this, SLOT( updateSemiToneMarkerMenu() ) ); - tb_layout->addSpacing( 5 ); + tb_layout->addSpacing( 4 ); tb_layout->addWidget( m_playButton ); tb_layout->addWidget( m_recordButton ); tb_layout->addWidget( m_recordAccompanyButton ); tb_layout->addWidget( m_stopButton ); - tb_layout->addSpacing( 10 ); + tb_layout->addSpacing( 7 ); tb_layout->addWidget( m_drawButton ); tb_layout->addWidget( m_eraseButton ); tb_layout->addWidget( m_selectButton ); tb_layout->addWidget( m_detuneButton ); - tb_layout->addSpacing( 10 ); + tb_layout->addSpacing( 7 ); tb_layout->addWidget( m_cutButton ); tb_layout->addWidget( m_copyButton ); tb_layout->addWidget( m_pasteButton ); - tb_layout->addSpacing( 10 ); + tb_layout->addSpacing( 7 ); m_timeLine->addToolButtons( m_toolBar ); - tb_layout->addSpacing( 15 ); + tb_layout->addSpacing( 7 ); tb_layout->addWidget( zoom_lbl ); tb_layout->addSpacing( 4 ); tb_layout->addWidget( m_zoomingComboBox ); diff --git a/src/gui/widgets/graph.cpp b/src/gui/widgets/graph.cpp index dc0246eb0..e3f20391b 100644 --- a/src/gui/widgets/graph.cpp +++ b/src/gui/widgets/graph.cpp @@ -34,7 +34,8 @@ #include "engine.h" -graph::graph( QWidget * _parent, graphStyle _style ) : +graph::graph( QWidget * _parent, graphStyle _style, int _width, + int _height ) : QWidget( _parent ), /* TODO: size, background? */ ModelView( new graphModel( -1.0, 1.0, 128, NULL, true ), this ), @@ -43,7 +44,7 @@ graph::graph( QWidget * _parent, graphStyle _style ) : m_mouseDown = false; m_graphColor = QColor( 0xFF, 0xAA, 0x00 ); - resize( 132, 104 ); + resize( _width, _height ); setAcceptDrops( true ); setCursor( Qt::CrossCursor ); @@ -76,7 +77,7 @@ void graph::setGraphColor( QColor _graphcol ) /* void graph::loadSampleFromFile( const QString & _filename ) { - + int i; // zero sample_shape @@ -84,7 +85,7 @@ void graph::loadSampleFromFile( const QString & _filename ) { samplePointer[i] = 0; } - + // load user shape sampleBuffer buffer( _filename ); @@ -107,34 +108,38 @@ void graph::mouseMoveEvent ( QMouseEvent * _me ) int x = _me->x(); int y = _me->y(); - static bool skip = false; +/* static bool skip = false; if( skip ) { skip = false; return; } - +*/ // avoid mouse leaps int diff = x - m_lastCursorX; - if( diff >= 1 ) +/* if( diff >= 1 ) { - x = qMin( width() - 2, m_lastCursorX + 1); + x = qMin( width() - 3, m_lastCursorX + 1 ); } - else if( diff <= 1 ) + else if( diff <= -1 ) { x = qMax( 2, m_lastCursorX - 1 ); + }*/ + + x = qMax( 2, qMin( x, width()-3 ) ); + y = qMax( 2, qMin( y, height()-3 ) ); + + if( qAbs( diff ) > 1 ) + { + drawLineAt( x, y, m_lastCursorX ); } else { - x = m_lastCursorX; + changeSampleAt( x, y ); } - y = qMax( 2, qMin( y, height()-3 ) ); - - changeSampleAt( x, y ); - // update mouse if( diff != 0 ) { @@ -145,7 +150,7 @@ void graph::mouseMoveEvent ( QMouseEvent * _me ) QCursor::setPos( pt.x(), pt.y() ); } - skip = true; +// skip = true; } @@ -154,25 +159,73 @@ void graph::mousePressEvent( QMouseEvent * _me ) { if( _me->button() == Qt::LeftButton ) { - // toggle mouse state - m_mouseDown = true; + if ( !( _me->modifiers() & Qt::ShiftModifier ) ) + { + // get position + int x = _me->x(); + int y = _me->y(); - // get position - int x = _me->x(); - int y = _me->y(); + changeSampleAt( x, y ); - changeSampleAt( x, y ); + // toggle mouse state + m_mouseDown = true; + setCursor( Qt::BlankCursor ); + m_lastCursorX = x; + } + else + { + //when shift-clicking, draw a line from last position to current + //position + int x = _me->x(); + int y = _me->y(); + + drawLineAt( x, y, m_lastCursorX ); + + m_mouseDown = true; + setCursor( Qt::BlankCursor ); + m_lastCursorX = x; + } - // toggle mouse state - m_mouseDown = true; - setCursor( Qt::BlankCursor ); - m_lastCursorX = x; } } +void graph::drawLineAt( int _x, int _y, int _lastx ) +{ + float minVal = model()->minValue(); + float maxVal = model()->maxValue(); + if ( width() <= 4 ) + { + return; + } + float xscale = static_cast( model()->length() ) / + ( width()-4 ); -void graph::changeSampleAt(int _x, int _y) + //consider border + _x -= 2; + _y -= 2; + _lastx -= 2; + + _lastx = qMax( 0, qMin( _lastx, width()-5 ) ); + + float range = minVal - maxVal; + float val = ( _y*range/( height()-4 ) ) + maxVal; + float lastval = model() -> m_samples[ (int)( _lastx * xscale ) ]; + + // calculate line drawing variables + int linelen = qAbs( _x - _lastx ) + 1; + int xstep = _x > _lastx ? -1 : 1; + float ystep = ( lastval - val ) / linelen; + + // draw a line + for ( int i = 0; i < linelen; i++ ) + { + int x = (_x + (i * xstep)); // get x value + model()->setSampleAt( (int)( x * xscale ), val + (i * ystep)); + } +} + +void graph::changeSampleAt( int _x, int _y ) { float minVal = model()->minValue(); float maxVal = model()->maxValue(); @@ -208,7 +261,7 @@ void graph::mouseReleaseEvent( QMouseEvent * _me ) setCursor( Qt::CrossCursor ); update(); } -} +} @@ -221,7 +274,7 @@ void graph::paintEvent( QPaintEvent * ) QVector * samps = &(model()->m_samples); int length = model()->length(); const float maxVal = model()->maxValue(); - + float xscale = (float)( width()-4 ) / length; float yscale = (float)( height()-4 ) / ( model()->minValue() - maxVal ); @@ -231,23 +284,24 @@ void graph::paintEvent( QPaintEvent * ) switch( m_graphStyle ) { - case graph::LinearStyle: + case graph::LinearStyle: p.setRenderHints( QPainter::Antialiasing, true ); for( int i=0; i < length; i++ ) { // Needs to be rewritten - p.drawLine(2+static_cast(i*xscale), + p.drawLine( + 2+static_cast(i*xscale), 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ), - 2+static_cast((i+1)*xscale), + 2+static_cast((i+1)*xscale), 2+static_cast( ( (*samps)[i+1] - maxVal ) * yscale ) ); } // Draw last segment wrapped around - p.drawLine(2+static_cast(length*xscale), + p.drawLine(2+static_cast(length*xscale), 2+static_cast( ( (*samps)[length] - maxVal ) * yscale ), - width()-2, + width()-3, 2+static_cast( ( (*samps)[0] - maxVal ) * yscale ) ); p.setRenderHints( QPainter::Antialiasing, false ); @@ -257,23 +311,43 @@ void graph::paintEvent( QPaintEvent * ) case graph::NearestStyle: for( int i=0; i < length; i++ ) { - p.drawLine(2+static_cast(i*xscale), + p.drawLine(2+static_cast(i*xscale), 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ), - 2+static_cast((i+1)*xscale), + 2+static_cast((i+1)*xscale), 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ) ); - p.drawLine(2+static_cast((i+1)*xscale), + p.drawLine(2+static_cast((i+1)*xscale), 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ), - 2+static_cast((i+1)*xscale), + 2+static_cast((i+1)*xscale), 2+static_cast( ( (*samps)[i+1] - maxVal ) * yscale ) ); } - p.drawLine(2+static_cast(length*xscale), + p.drawLine(2+static_cast(length*xscale), 2+static_cast( ( (*samps)[length] - maxVal ) * yscale ), - width()-2, + width()-3, 2+static_cast( ( (*samps)[length] - maxVal ) * yscale ) ); break; + + case graph::LinearNonCyclicStyle: + p.setRenderHints( QPainter::Antialiasing, true ); + + for( int i=0; i < length; i++ ) + { + // Needs to be rewritten + p.drawLine( + 2+static_cast(i*xscale), + 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ), + 2+static_cast((i+1)*xscale), + 2+static_cast( ( (*samps)[i+1] - maxVal ) * yscale ) + ); + } + + // Do not draw last segment wrapped around - hence, "non-cyclic" + + p.setRenderHints( QPainter::Antialiasing, false ); + break; + default: break; @@ -281,7 +355,7 @@ void graph::paintEvent( QPaintEvent * ) // draw Pointer - if( m_mouseDown ) + if( m_mouseDown ) { QPoint cursor = mapFromGlobal( QCursor::pos() ); p.setPen( QColor( 0xAA, 0xFF, 0x00, 0x70 ) ); @@ -369,7 +443,7 @@ void graphModel::setRange( float _min, float _max ) if( !m_samples.isEmpty() ) { - // Trim existing values + // Trim existing values for( int i=0; i < length(); i++ ) { m_samples[i] = fmaxf( _min, fminf( m_samples[i], _max ) ); @@ -397,15 +471,14 @@ void graphModel::setSampleAt( int _x, float _val ) { //snap to the grid _val -= ( m_step != 0.0 ) ? fmod( _val, m_step ) * m_step : 0; - // boundary check - if ( _x >= 0 && _x < length() && - _val >= minValue() && _val < maxValue() ) - { - // change sample shape - m_samples[_x] = _val; - emit samplesChanged( _x, _x ); - } + // boundary crop + _x = qMax( 0, qMin( length()-1, _x ) ); + _val = qMax( minValue(), qMin( maxValue(), _val ) ); + + // change sample shape + m_samples[_x] = _val; + emit samplesChanged( _x, _x ); } @@ -509,16 +582,31 @@ void graphModel::smooth() QVector temp = m_samples; // Smoothing - m_samples[0] = ( temp[0] + temp[length()-1] ) * 0.5f; - for ( int i=1; i < length(); i++ ) + m_samples[0] = ( temp[length()-1] + ( temp[0] * 2 ) + temp[1] ) * 0.25f; + for ( int i=1; i < ( length()-1 ); i++ ) { - m_samples[i] = ( temp[i-1] + temp[i] ) * 0.5f; + m_samples[i] = ( temp[i-1] + ( temp[i] * 2 ) + temp[i+1] ) * 0.25f; } + m_samples[length()-1] = ( temp[length()-2] + ( temp[length()-1] * 2 ) + temp[0] ) * 0.25f; emit samplesChanged(0, length()-1); } +void graphModel::smoothNonCyclic() +{ + // store values in temporary array + QVector temp = m_samples; + // Smoothing + m_samples[0] = ( ( temp[0] * 2 ) + temp[1] ) / 3.0f; + for ( int i=1; i < ( length()-1 ); i++ ) + { + m_samples[i] = ( temp[i-1] + ( temp[i] * 2 ) + temp[i+1] ) * 0.25f; + } + m_samples[length()-1] = ( temp[length()-2] + ( temp[length()-1] * 2 ) ) / 3.0f; + + emit samplesChanged(0, length()-1); +} void graphModel::normalize() { @@ -539,7 +627,7 @@ void graphModel::normalize() if( max != 1.0f ) { emit samplesChanged( 0, length()-1 ); } -} +}