Merge pull request #302 from diizy/waveshaper

Waveshaper
This commit is contained in:
Tobias Doerffel
2014-02-12 23:23:35 +01:00
19 changed files with 745 additions and 62 deletions

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
plugins/waveshaper/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,154 @@
/*
* waveshaper.cpp - waveshaper effect-plugin
*
* * Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright (c) 2006-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <math.h>
#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 <contact/dot/diizy/at/nbl/dot/fi>",
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<const Plugin::Descriptor::SubPluginFeatures::Key *>(
_data ) ) );
}
}

View File

@@ -0,0 +1,63 @@
/*
* waveshaper.h - bass-booster-effect-plugin
*
* * Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright (c) 2006-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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

View File

@@ -0,0 +1,89 @@
/*
* waveshaper_control_dialog.cpp - control-dialog for waveshaper-effect
*
* Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright * (c) 2006-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <QtGui/QLayout>
#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() ) );
}

View File

@@ -0,0 +1,48 @@
/*
* waveshaper_control_dialog.h - control-dialog for waveshaper-effect
*
* * Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright (c) 2006-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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

View File

@@ -0,0 +1,144 @@
/*
* waveshaper_controls.cpp - controls for waveshaper-effect
*
* Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <QtXml/QDomElement>
#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"

View File

@@ -0,0 +1,85 @@
/*
* waveshaper_controls.h - controls for waveshaper-effect
*
* Copyright * (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

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

View File

@@ -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<float>( 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<float> * 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<int>(i*xscale),
p.drawLine(
2+static_cast<int>(i*xscale),
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>( ( (*samps)[i+1] - maxVal ) * yscale )
);
}
// Draw last segment wrapped around
p.drawLine(2+static_cast<int>(length*xscale),
p.drawLine(2+static_cast<int>(length*xscale),
2+static_cast<int>( ( (*samps)[length] - maxVal ) * yscale ),
width()-2,
width()-3,
2+static_cast<int>( ( (*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<int>(i*xscale),
p.drawLine(2+static_cast<int>(i*xscale),
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale )
);
p.drawLine(2+static_cast<int>((i+1)*xscale),
p.drawLine(2+static_cast<int>((i+1)*xscale),
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>( ( (*samps)[i+1] - maxVal ) * yscale )
);
}
p.drawLine(2+static_cast<int>(length*xscale),
p.drawLine(2+static_cast<int>(length*xscale),
2+static_cast<int>( ( (*samps)[length] - maxVal ) * yscale ),
width()-2,
width()-3,
2+static_cast<int>( ( (*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<int>(i*xscale),
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ),
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>( ( (*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<float> 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<float> 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 );
}
}
}