steroEnhancer, Vibed, and separated Graph widget
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/branches/lmms-mv@699 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
33
ChangeLog
33
ChangeLog
@@ -1,3 +1,36 @@
|
||||
2008-02-22 Paul Giblock <pgllama/at/gmail/dot/com>
|
||||
|
||||
* plugins/vibed/vibed.cpp:
|
||||
* plugins/vibed/vibed.h:
|
||||
* plugins/vibed/string_container.cpp:
|
||||
* plugins/vibed/string_container.h:
|
||||
* plugins/vibed/nine_button_selector.cpp:
|
||||
* plugins/vibed/nine_button_selector.h:
|
||||
* plugins/vibed/Makefile.am:
|
||||
M/V-split of Vibed-instrument. Lacks user-specified wave, to be added on
|
||||
my next commit. Also has an audio output bug, certain notes make weird
|
||||
noises
|
||||
|
||||
* plugins/stereo_enhancer/stereoenhancer_controls.cpp:
|
||||
* plugins/stereo_enhancer/stereoenhancer_controls.h:
|
||||
* plugins/stereo_enhancer/stereo_enhancer.cpp:
|
||||
* plugins/stereo_enhancer/stereo_enhancer.h:
|
||||
* plugins/stereo_enhancer/stereoenhancer_control_dialog.cpp:
|
||||
* plugins/stereo_enhancer/stereoenhancer_control_dialog.h:
|
||||
* plugins/stereo_enhancer/Makefile.am:
|
||||
M/V-split of Stereo-enhancer effect.
|
||||
|
||||
* src/core/piano_roll.cpp:
|
||||
Changed quantization to change on the gridlines, instead of nearest-point
|
||||
in the middle. Made this change here, because MIDI events should still be
|
||||
quantized to nearest-point (I think)
|
||||
|
||||
* src/widgets/graph.cpp:
|
||||
* include/graph.h:
|
||||
* Makefile.am:
|
||||
Split graph and moved it to the shared widgets. Supports variable ranges,
|
||||
sample-lengths, smoothing, normalizing, and is antialiased
|
||||
|
||||
2008-02-18 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/ladspa_effect/ladspa_subplugin_features.h:
|
||||
|
||||
@@ -67,6 +67,7 @@ lmms_MOC = \
|
||||
./export_project_dialog.moc \
|
||||
./fade_button.moc \
|
||||
./file_browser.moc \
|
||||
./graph.moc \
|
||||
./group_box.moc \
|
||||
./instrument_midi_io.moc \
|
||||
./instrument_midi_io_view.moc \
|
||||
@@ -223,6 +224,7 @@ lmms_SOURCES = \
|
||||
$(srcdir)/src/widgets/effect_rack_view.cpp \
|
||||
$(srcdir)/src/widgets/effect_view.cpp \
|
||||
$(srcdir)/src/widgets/fade_button.cpp \
|
||||
$(srcdir)/src/widgets/graph.cpp \
|
||||
$(srcdir)/src/widgets/group_box.cpp \
|
||||
$(srcdir)/src/widgets/envelope_and_lfo_view.cpp \
|
||||
$(srcdir)/src/widgets/instrument_function_views.cpp \
|
||||
@@ -303,6 +305,7 @@ lmms_SOURCES = \
|
||||
$(srcdir)/include/mv_base.h \
|
||||
$(srcdir)/include/automatable_model.h \
|
||||
$(srcdir)/include/automatable_model_templates.h \
|
||||
$(srcdir)/include/graph.h \
|
||||
$(srcdir)/include/group_box.h \
|
||||
$(srcdir)/include/tab_widget.h \
|
||||
$(srcdir)/include/knob.h \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* graph.h - a QT widget for displaying and manipulating waveforms
|
||||
*
|
||||
* Copyright (c) 2006-2007 Andreas Brandmaier <andy/at/brandmaier/dot/de>
|
||||
* 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -30,21 +31,26 @@
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QCursor>
|
||||
|
||||
#include "mv_base.h"
|
||||
#include "types.h"
|
||||
|
||||
class graph : public QWidget
|
||||
class graphModel;
|
||||
class track;
|
||||
|
||||
class graph : public QWidget, public modelView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
graph( QWidget * _parent );
|
||||
virtual ~graph();
|
||||
|
||||
void setSamplePointer( float * pointer, int length );
|
||||
void setForeground( const QPixmap & _pixmap );
|
||||
void loadSampleFromFile( const QString & _filename );
|
||||
// void loadSampleFromFile( const QString & _filename );
|
||||
|
||||
virtual inline graphModel * model( void ) {
|
||||
return castModel<graphModel>();
|
||||
}
|
||||
|
||||
signals:
|
||||
void sampleSizeChanged( float f );
|
||||
void sampleChanged( void );
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
@@ -54,19 +60,90 @@ protected:
|
||||
virtual void mouseMoveEvent( QMouseEvent * _me );
|
||||
virtual void mouseReleaseEvent( QMouseEvent * _me );
|
||||
|
||||
protected slots:
|
||||
void updateGraph(Uint32 _startPos, Uint32 _endPos);
|
||||
|
||||
private:
|
||||
virtual void modelChanged( void );
|
||||
|
||||
void changeSampleAt(int _x, int _y);
|
||||
|
||||
|
||||
QPixmap m_foreground;
|
||||
|
||||
graphModel * m_graphModel;
|
||||
|
||||
float *samplePointer;
|
||||
int sampleLength;
|
||||
|
||||
bool m_mouseDown;
|
||||
int m_lastCursorX;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
class graphModel : public model
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
graphModel( float _min,
|
||||
float _max,
|
||||
Uint32 _size,
|
||||
:: model * _parent, track * _track = NULL,
|
||||
bool _default_constructed = FALSE );
|
||||
|
||||
virtual ~graphModel();
|
||||
|
||||
// TODO: saveSettings, loadSettings?
|
||||
|
||||
inline float minValue( void ) const
|
||||
{
|
||||
return( m_minValue );
|
||||
}
|
||||
|
||||
inline float maxValue( void ) const
|
||||
{
|
||||
return( m_maxValue );
|
||||
}
|
||||
|
||||
inline Uint32 length( void ) const
|
||||
{
|
||||
return( m_samples.count() );
|
||||
}
|
||||
|
||||
inline const float* samples( void ) const
|
||||
{
|
||||
return( m_samples.data() );
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setRange( float _min, float _max );
|
||||
|
||||
void setLength( Uint32 _size );
|
||||
|
||||
void setSampleAt( Uint32 _samplePos, float _value );
|
||||
void setSamples( const float * _value );
|
||||
|
||||
void setWaveToSine( void );
|
||||
void setWaveToTriangle( void );
|
||||
void setWaveToSaw( void );
|
||||
void setWaveToSquare( void );
|
||||
void setWaveToNoise( void );
|
||||
//void setWaveToUser( );
|
||||
|
||||
void smooth( void );
|
||||
void normalize( void );
|
||||
|
||||
signals:
|
||||
void lengthChanged( void );
|
||||
void samplesChanged( Uint32 startPos, Uint32 endPos );
|
||||
void rangeChanged( void );
|
||||
|
||||
private:
|
||||
|
||||
QVector<float> m_samples;
|
||||
float m_maxValue;
|
||||
float m_minValue;
|
||||
|
||||
friend class graph;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@ AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="stereoenhancer"
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./stereoenhancer_control_dialog.moc
|
||||
MOC_FILES = ./stereoenhancer_controls.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
@@ -31,6 +31,8 @@ pkglib_LTLIBRARIES= libstereoenhancer.la
|
||||
libstereoenhancer_la_SOURCES = stereo_enhancer.cpp \
|
||||
stereo_enhancer.h \
|
||||
stereoenhancer_control_dialog.cpp \
|
||||
stereoenhancer_control_dialog.h
|
||||
stereoenhancer_control_dialog.h \
|
||||
stereoenhancer_controls.cpp \
|
||||
stereoenhancer_controls.h
|
||||
|
||||
$(libstereoenhancer_la_SOURCES): ./embedded_resources.h
|
||||
|
||||
@@ -51,11 +51,13 @@ plugin::descriptor stereoenhancer_plugin_descriptor =
|
||||
|
||||
|
||||
stereoEnhancerEffect::stereoEnhancerEffect(
|
||||
model * _parent,
|
||||
const descriptor::subPluginFeatures::key * _key ) :
|
||||
effect( &stereoenhancer_plugin_descriptor, _key ),
|
||||
effect( &stereoenhancer_plugin_descriptor, _parent, _key ),
|
||||
m_seFX( effectLib::stereoEnhancer<>( 0.0f ) ),
|
||||
m_delayBuffer( new surroundSampleFrame[DEFAULT_BUFFER_SIZE] ),
|
||||
m_currFrame( 0 )
|
||||
m_currFrame( 0 ),
|
||||
m_bbControls( this )
|
||||
{
|
||||
// TODO: Make m_delayBuffer customizable?
|
||||
}
|
||||
@@ -89,7 +91,7 @@ bool FASTCALL stereoEnhancerEffect::processAudioBuffer( surroundSampleFrame * _b
|
||||
int frameIndex = 0;
|
||||
|
||||
|
||||
if( isBypassed() || !isRunning () )
|
||||
if( !isEnabled() || !isRunning() )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
@@ -123,7 +125,7 @@ bool FASTCALL stereoEnhancerEffect::processAudioBuffer( surroundSampleFrame * _b
|
||||
_buf[f][ch] = getDryLevel() * _buf[f][ch] +
|
||||
getWetLevel() *
|
||||
s[ch%DEFAULT_CHANNELS];
|
||||
out_sum += _buf[f][ch]*_buf[f][ch];
|
||||
out_sum += _buf[f][ch]*_buf[f][ch];
|
||||
}
|
||||
|
||||
// Update currFrame
|
||||
@@ -170,9 +172,9 @@ extern "C"
|
||||
{
|
||||
|
||||
// neccessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( void * _data )
|
||||
plugin * lmms_plugin_main( model * _parent, void * _data )
|
||||
{
|
||||
return( new stereoEnhancerEffect(
|
||||
return( new stereoEnhancerEffect( _parent,
|
||||
static_cast<const plugin::descriptor::subPluginFeatures::key *>(
|
||||
_data ) ) );
|
||||
}
|
||||
|
||||
@@ -32,43 +32,36 @@
|
||||
#include "effect_lib.h"
|
||||
#include "engine.h"
|
||||
#include "main_window.h"
|
||||
#include "stereoenhancer_control_dialog.h"
|
||||
#include "stereoenhancer_controls.h"
|
||||
|
||||
class stereoEnhancerEffect : public effect
|
||||
{
|
||||
public:
|
||||
stereoEnhancerEffect( const descriptor::subPluginFeatures::key * _key );
|
||||
stereoEnhancerEffect( model * parent,
|
||||
const descriptor::subPluginFeatures::key * _key );
|
||||
virtual ~stereoEnhancerEffect();
|
||||
virtual bool FASTCALL processAudioBuffer( surroundSampleFrame * _buf,
|
||||
const fpp_t _frames );
|
||||
inline virtual QString nodeName( void ) const
|
||||
const fpp_t _frames );
|
||||
|
||||
virtual effectControls * getControls( void )
|
||||
{
|
||||
return( "stereoenhancereffect" );
|
||||
return( &m_bbControls );
|
||||
}
|
||||
|
||||
virtual inline effectControlDialog * createControlDialog( track * )
|
||||
{
|
||||
return( new stereoEnhancerControlDialog(
|
||||
engine::getMainWindow()->workspace(),
|
||||
this ) );
|
||||
}
|
||||
|
||||
void clearMyBuffer();
|
||||
|
||||
|
||||
private:
|
||||
//effectLib::monoToStereoAdaptor<effectLib::stereoEnhancer<> > m_seFX;
|
||||
effectLib::stereoEnhancer<> m_seFX;
|
||||
|
||||
surroundSampleFrame * m_delayBuffer;
|
||||
int m_currFrame;
|
||||
|
||||
stereoEnhancerControls m_bbControls;
|
||||
|
||||
friend class stereoEnhancerControlDialog;
|
||||
friend class stereoEnhancerControls;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,68 +23,27 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QT3
|
||||
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QMdiArea>
|
||||
|
||||
#else
|
||||
|
||||
#include <qlayout.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "stereo_enhancer.h"
|
||||
#include "knob.h"
|
||||
#include "stereoenhancer_control_dialog.h"
|
||||
#include "stereoenhancer_controls.h"
|
||||
|
||||
|
||||
|
||||
stereoEnhancerControlDialog::stereoEnhancerControlDialog( QMdiArea * _parent,
|
||||
stereoEnhancerEffect * _eff ) :
|
||||
effectControlDialog( _parent, _eff ),
|
||||
m_effect( _eff )
|
||||
stereoEnhancerControlDialog::stereoEnhancerControlDialog(
|
||||
stereoEnhancerControls * _controls ) :
|
||||
effectControlDialog( _controls )
|
||||
{
|
||||
QHBoxLayout * l = new QHBoxLayout( this );
|
||||
|
||||
m_widthKnob = new knob( knobBright_26, this, tr( "Width" ), NULL );
|
||||
m_widthKnob->setRange( 0.0f, 180.0f, 1.0f );
|
||||
m_widthKnob->setInitValue( 0.0f );
|
||||
m_widthKnob->setLabel( tr( "WIDE" ) );
|
||||
m_widthKnob->setHintText( tr( "Width:" ) + " ", "samples" );
|
||||
connect( m_widthKnob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT( changeWideCoeff( void ) ) );
|
||||
knob * widthKnob = new knob( knobBright_26, this, tr( "Width" ) );
|
||||
widthKnob->setModel( &_controls->m_widthModel );
|
||||
widthKnob->setLabel( tr( "WIDE" ) );
|
||||
widthKnob->setHintText( tr( "Width:" ) + " ", "samples" );
|
||||
|
||||
l->addWidget( m_widthKnob );
|
||||
l->addWidget( widthKnob );
|
||||
|
||||
changeWideCoeff();
|
||||
this->setLayout(l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void stereoEnhancerControlDialog::changeWideCoeff( void )
|
||||
{
|
||||
m_effect->m_seFX.setWideCoeff( m_widthKnob->value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FASTCALL stereoEnhancerControlDialog::loadSettings(
|
||||
const QDomElement & _this )
|
||||
{
|
||||
m_widthKnob->setValue( _this.attribute( "width" ).toFloat() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FASTCALL stereoEnhancerControlDialog::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "width", m_widthKnob->value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "stereoenhancer_control_dialog.moc"
|
||||
|
||||
|
||||
@@ -27,42 +27,18 @@
|
||||
|
||||
#include "effect_control_dialog.h"
|
||||
|
||||
class knob;
|
||||
class stereoEnhancerEffect;
|
||||
class QMdiArea;
|
||||
class stereoEnhancerControls;
|
||||
|
||||
|
||||
class stereoEnhancerControlDialog : public effectControlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
stereoEnhancerControlDialog( QMdiArea * _parent, stereoEnhancerEffect * _eff );
|
||||
stereoEnhancerControlDialog( stereoEnhancerControls * _controls );
|
||||
virtual ~stereoEnhancerControlDialog()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
inline virtual QString nodeName( void ) const
|
||||
{
|
||||
return( "stereoenhancercontrols" );
|
||||
}
|
||||
};
|
||||
|
||||
virtual ch_cnt_t getControlCount( void )
|
||||
{
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
private slots:
|
||||
void changeWideCoeff( void );
|
||||
|
||||
|
||||
private:
|
||||
stereoEnhancerEffect * m_effect;
|
||||
knob * m_widthKnob;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
68
plugins/stereo_enhancer/stereoenhancer_controls.cpp
Normal file
68
plugins/stereo_enhancer/stereoenhancer_controls.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* stereoenhancer_controls.cpp - control-dialog for stereoenhancer-effect
|
||||
*
|
||||
* 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 "stereoenhancer_controls.h"
|
||||
#include "stereo_enhancer.h"
|
||||
#include "automatable_model_templates.h"
|
||||
|
||||
|
||||
stereoEnhancerControls::stereoEnhancerControls( stereoEnhancerEffect * _eff ) :
|
||||
effectControls( _eff ),
|
||||
m_effect( _eff ),
|
||||
m_widthModel(0.0f, 0.0f, 180.0f, 1.0f)
|
||||
{
|
||||
connect( &m_widthModel, SIGNAL( dataChanged( void ) ),
|
||||
this, SLOT( changeWideCoeff( void ) ) );
|
||||
|
||||
changeWideCoeff();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void stereoEnhancerControls::changeWideCoeff( void )
|
||||
{
|
||||
m_effect->m_seFX.setWideCoeff( m_widthModel.value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FASTCALL stereoEnhancerControls::loadSettings(
|
||||
const QDomElement & _this )
|
||||
{
|
||||
m_widthModel.setValue( _this.attribute( "width" ).toFloat() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FASTCALL stereoEnhancerControls::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "width", m_widthModel.value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "stereoenhancer_controls.moc"
|
||||
|
||||
74
plugins/stereo_enhancer/stereoenhancer_controls.h
Normal file
74
plugins/stereo_enhancer/stereoenhancer_controls.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* stereoenhancer_controls.h - controls for stereoEnhancer-effect
|
||||
*
|
||||
* 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 _STEREO_ENHANCER_CONTROLS_H
|
||||
#define _STEREO_ENHANCER_CONTROLS_H
|
||||
|
||||
#include "effect_controls.h"
|
||||
#include "stereoenhancer_control_dialog.h"
|
||||
#include "knob.h"
|
||||
|
||||
class stereoEnhancerEffect;
|
||||
|
||||
class stereoEnhancerControls : public effectControls
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
stereoEnhancerControls( stereoEnhancerEffect( * _eff ) );
|
||||
virtual ~stereoEnhancerControls()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
inline virtual QString nodeName( void ) const
|
||||
{
|
||||
return( "stereoenhancercontrols" );
|
||||
}
|
||||
|
||||
virtual ch_cnt_t getControlCount( void )
|
||||
{
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
virtual effectControlDialog * createView( void )
|
||||
{
|
||||
return new stereoEnhancerControlDialog( this );
|
||||
}
|
||||
|
||||
|
||||
private slots:
|
||||
void changeWideCoeff( void );
|
||||
|
||||
|
||||
private:
|
||||
stereoEnhancerEffect * m_effect;
|
||||
knobModel m_widthModel;
|
||||
|
||||
friend class stereoEnhancerControlDialog;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif /*_STEREO_ENHANCER_CONTROLS_H*/
|
||||
@@ -11,7 +11,7 @@ AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="vibedstrings"
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./vibed.moc ./graph.moc ./impulse_editor.moc ./nine_button_selector.moc
|
||||
MOC_FILES = ./vibed.moc ./nine_button_selector.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
@@ -30,15 +30,11 @@ pkglib_LTLIBRARIES= libvibedstrings.la
|
||||
|
||||
libvibedstrings_la_SOURCES = vibed.cpp \
|
||||
vibed.h \
|
||||
graph.cpp \
|
||||
graph.h \
|
||||
vibrating_string.cpp \
|
||||
vibrating_string.h \
|
||||
nine_button_selector.cpp \
|
||||
nine_button_selector.h \
|
||||
string_container.cpp \
|
||||
string_container.h \
|
||||
impulse_editor.cpp \
|
||||
impulse_editor.h \
|
||||
nine_button_selector.cpp \
|
||||
nine_button_selector.h
|
||||
string_container.h
|
||||
|
||||
$(libvibedstrings_la_SOURCES): ./embedded_resources.h
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
* graph.cpp - a QT widget for displaying and manipulating waveforms
|
||||
*
|
||||
* Copyright (c) 2006-2007 Andreas Brandmaier <andy/at/brandmaier/dot/de>
|
||||
*
|
||||
* 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/QPaintEvent>
|
||||
#include <QtGui/QFontMetrics>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
#include "graph.h"
|
||||
#include "string_pair_drag.h"
|
||||
#include "sample_buffer.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
graph::graph( QWidget * _parent ) :
|
||||
QWidget( _parent )
|
||||
{
|
||||
m_mouseDown = false;
|
||||
|
||||
setFixedSize( 132, 104 );
|
||||
|
||||
setAcceptDrops( TRUE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
graph::~graph()
|
||||
{
|
||||
}
|
||||
|
||||
void graph::setForeground( const QPixmap &_pixmap )
|
||||
{
|
||||
m_foreground = _pixmap;
|
||||
}
|
||||
|
||||
void graph::setSamplePointer( float * _pointer, int _length )
|
||||
{
|
||||
samplePointer = _pointer;
|
||||
sampleLength = _length;
|
||||
update();
|
||||
}
|
||||
|
||||
void graph::loadSampleFromFile( const QString & _filename )
|
||||
{
|
||||
// zero sample_shape
|
||||
for (int i = 0; i < sampleLength; i++)
|
||||
{
|
||||
samplePointer[i] = 0;
|
||||
}
|
||||
|
||||
// load user shape
|
||||
sampleBuffer buffer( _filename );
|
||||
|
||||
// copy buffer data
|
||||
sampleLength = min( sampleLength, static_cast<int>(buffer.frames()) );
|
||||
for ( int i = 0; i < sampleLength; i++ )
|
||||
{
|
||||
samplePointer[i] = (float)*buffer.data()[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void graph::mouseMoveEvent ( QMouseEvent * _me )
|
||||
{
|
||||
// get position
|
||||
int x = _me->x();
|
||||
int y = _me->y();
|
||||
|
||||
|
||||
// avoid mouse leaps
|
||||
int diff = x - m_lastCursorX;
|
||||
|
||||
if( diff >= 1 )
|
||||
{
|
||||
x = m_lastCursorX + 1;
|
||||
}
|
||||
else if( diff <= 1 )
|
||||
{
|
||||
x = m_lastCursorX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = m_lastCursorX;
|
||||
}
|
||||
|
||||
changeSampleAt( x, y );
|
||||
|
||||
// update mouse
|
||||
m_lastCursorX = x;
|
||||
|
||||
}
|
||||
|
||||
void graph::mousePressEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() == Qt::LeftButton )
|
||||
{
|
||||
// toggle mouse state
|
||||
m_mouseDown = true;
|
||||
|
||||
// get position
|
||||
int x = _me->x();
|
||||
int y = _me->y();
|
||||
|
||||
changeSampleAt( x,y );
|
||||
|
||||
// toggle mouse state
|
||||
m_mouseDown = true;
|
||||
setCursor( Qt::BlankCursor );
|
||||
m_lastCursorX = x;
|
||||
}
|
||||
}
|
||||
|
||||
void graph::changeSampleAt(int _x, int _y)
|
||||
{
|
||||
// consider border of background image
|
||||
_x -= 2;
|
||||
_y -= 2;
|
||||
|
||||
// boundary check
|
||||
if (_x < 0) { return; }
|
||||
if (_x > sampleLength) { return; }
|
||||
if (_y < 0) { return; }
|
||||
if (_y >= 100) { return; }
|
||||
_y = 100 - _y;
|
||||
|
||||
// change sample shape
|
||||
samplePointer[_x] = (_y-50.0)/50.0;
|
||||
emit sampleChanged();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void graph::mouseReleaseEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() == Qt::LeftButton )
|
||||
{
|
||||
// toggle mouse state
|
||||
m_mouseDown = false;
|
||||
setCursor( Qt::ArrowCursor );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::paintEvent( QPaintEvent * )
|
||||
{
|
||||
|
||||
QPainter p( this );
|
||||
|
||||
p.setPen( QColor( 0xFF, 0xAA, 0x00 ) );
|
||||
|
||||
p.drawLine( 1+sampleLength, 2, 1+sampleLength, 102);
|
||||
|
||||
float xscale = 128.0 / sampleLength;
|
||||
|
||||
for (int i=0; i < sampleLength-1; i++)
|
||||
{
|
||||
p.drawLine(2+static_cast<int>(i*xscale),
|
||||
2+static_cast<int>(-samplePointer[i]*50) + 50,
|
||||
2+static_cast<int>((i+1)*xscale),
|
||||
2+static_cast<int>(-samplePointer[i+1]*50 + 50)
|
||||
);
|
||||
}
|
||||
|
||||
// draw Pointer
|
||||
if (m_mouseDown) {
|
||||
QPoint cursor = mapFromGlobal( QCursor::pos() );
|
||||
p.setPen( QColor( 0xAA, 0xFF, 0x00 ) );
|
||||
p.drawLine( 2, cursor.y(), 130, cursor.y() );
|
||||
p.drawLine( cursor.x(), 2, cursor.x(), 102 );
|
||||
}
|
||||
p.drawPixmap( 0, 0, m_foreground );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void graph::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
QString type = stringPairDrag::decodeKey( _de );
|
||||
QString value = stringPairDrag::decodeValue( _de );
|
||||
|
||||
if( type == "samplefile" )
|
||||
{
|
||||
loadSampleFromFile( value );
|
||||
_de->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void graph::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
if( stringPairDrag::processDragEnterEvent( _dee,
|
||||
QString( "samplefile" ) ) == FALSE )
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include "graph.moc"
|
||||
@@ -1,471 +0,0 @@
|
||||
/*
|
||||
* impulse_editor.cpp - graphic waveform editor
|
||||
*
|
||||
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
|
||||
*
|
||||
* 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 "impulse_editor.h"
|
||||
|
||||
#include <Qt/QtXml>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QPoint>
|
||||
#include <QtGui/QWhatsThis>
|
||||
|
||||
#include "caption_menu.h"
|
||||
#include "embed.h"
|
||||
#include "engine.h"
|
||||
#include "oscillator.h"
|
||||
#include "song_editor.h"
|
||||
#include "tooltip.h"
|
||||
#include "vibed.h"
|
||||
|
||||
|
||||
impulseEditor::impulseEditor( QWidget * _parent, int _x, int _y, track * _track,
|
||||
Uint32 _len ) :
|
||||
QWidget( _parent ),
|
||||
m_sampleLength( _len ),
|
||||
m_normalizeFactor( 1.0f ),
|
||||
m_forward( TRUE )
|
||||
{
|
||||
setFixedSize( 153, 124 );
|
||||
m_base = QPixmap::grabWidget( _parent, _x, _y );
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal = palette();
|
||||
pal.setBrush( backgroundRole(), m_base );
|
||||
setPalette( pal );
|
||||
|
||||
m_graph = new graph( this );
|
||||
m_graph->setForeground( PLUGIN_NAME::getIconPixmap( "wavegraph4" ) );
|
||||
m_graph->move( 0, 0 );
|
||||
m_graph->setCursor( QCursor( Qt::CrossCursor ) );
|
||||
toolTip::add( m_graph, tr ( "Draw your own waveform here "
|
||||
"by dragging your mouse onto this graph" ) );
|
||||
|
||||
connect( m_graph, SIGNAL ( sampleChanged( void ) ),
|
||||
this, SLOT ( sampleChanged( void ) ) );
|
||||
|
||||
m_sinWaveBtn = new pixmapButton( this, tr( "Sine wave" ), _track );
|
||||
m_sinWaveBtn->move( 136, 3 );
|
||||
m_sinWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"sin_wave_active" ) );
|
||||
m_sinWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"sin_wave_inactive" ) );
|
||||
m_sinWaveBtn->setChecked( TRUE );
|
||||
toolTip::add( m_sinWaveBtn,
|
||||
tr( "Click here if you want a sine-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sinWaveBtn, SIGNAL (clicked ( void ) ),
|
||||
this, SLOT ( sinWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_triangleWaveBtn = new pixmapButton( this, tr( "Triangle wave" ),
|
||||
_track );
|
||||
m_triangleWaveBtn->move( 136, 20 );
|
||||
m_triangleWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap( "triangle_wave_active" ) );
|
||||
m_triangleWaveBtn->setInactiveGraphic(
|
||||
embed::getIconPixmap( "triangle_wave_inactive" ) );
|
||||
toolTip::add( m_triangleWaveBtn,
|
||||
tr( "Click here if you want a triangle-wave "
|
||||
"for current oscillator." ) );
|
||||
connect( m_triangleWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( triangleWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_sawWaveBtn = new pixmapButton( this, tr( "Saw wave" ), _track );
|
||||
m_sawWaveBtn->move( 136, 37 );
|
||||
m_sawWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"saw_wave_active" ) );
|
||||
m_sawWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"saw_wave_inactive" ) );
|
||||
toolTip::add( m_sawWaveBtn,
|
||||
tr( "Click here if you want a saw-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sawWaveBtn, SIGNAL (clicked ( void ) ),
|
||||
this, SLOT ( sawWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_sqrWaveBtn = new pixmapButton( this, tr( "Square wave" ), _track );
|
||||
m_sqrWaveBtn->move( 136, 54 );
|
||||
m_sqrWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"square_wave_active" ) );
|
||||
m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"square_wave_inactive" ) );
|
||||
toolTip::add( m_sqrWaveBtn,
|
||||
tr( "Click here if you want a square-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sqrWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( sqrWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_whiteNoiseWaveBtn = new pixmapButton( this, tr( "White noise wave" ),
|
||||
_track );
|
||||
m_whiteNoiseWaveBtn->move( 136, 71 );
|
||||
m_whiteNoiseWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap( "white_noise_wave_active" ) );
|
||||
m_whiteNoiseWaveBtn->setInactiveGraphic(
|
||||
embed::getIconPixmap( "white_noise_wave_inactive" ) );
|
||||
toolTip::add( m_whiteNoiseWaveBtn,
|
||||
tr( "Click here if you want a white-noise for "
|
||||
"current oscillator." ) );
|
||||
connect( m_whiteNoiseWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( noiseWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_usrWaveBtn = new pixmapButton( this, tr( "User defined wave" ),
|
||||
_track );
|
||||
m_usrWaveBtn->move( 136, 88 );
|
||||
m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"usr_wave_active" ) );
|
||||
m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"usr_wave_inactive" ) );
|
||||
toolTip::add( m_usrWaveBtn,
|
||||
tr( "Click here if you want a user-defined "
|
||||
"wave-shape for current oscillator." ) );
|
||||
connect( m_usrWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( usrWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_smoothBtn = new pixmapButton( this, tr( "Smooth" ), _track );
|
||||
m_smoothBtn->move( 3, 108 );
|
||||
m_smoothBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"smooth_active" ) );
|
||||
m_smoothBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"smooth_inactive" ) );
|
||||
m_smoothBtn->setChecked( FALSE );
|
||||
toolTip::add( m_smoothBtn,
|
||||
tr( "Click here to smooth waveform." ) );
|
||||
connect( m_smoothBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( smoothClicked( void ) ) );
|
||||
|
||||
|
||||
m_normalizeBtn = new pixmapButton( this, tr( "Normalize" ), _track );
|
||||
m_normalizeBtn->move( 20, 108 );
|
||||
m_normalizeBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"normalize_active" ) );
|
||||
m_normalizeBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"normalize_inactive" ) );
|
||||
m_normalizeBtn->setChecked( FALSE );
|
||||
toolTip::add( m_normalizeBtn,
|
||||
tr( "Click here to normalize waveform." ) );
|
||||
|
||||
connect( m_normalizeBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( normalizeClicked( void ) ) );
|
||||
|
||||
m_state = new ledCheckBox( "", this, tr( "Enable waveform" ), _track );
|
||||
m_state->move( 136, 109 );
|
||||
m_state->setChecked( TRUE );
|
||||
toolTip::add( m_state,
|
||||
tr( "Click here to enable/disable waveform." ) );
|
||||
|
||||
m_sampleShape = new float[m_sampleLength];
|
||||
m_graph->setSamplePointer( m_sampleShape, m_sampleLength );
|
||||
|
||||
m_lastBtn = m_sinWaveBtn;
|
||||
emit( sawWaveClicked() );
|
||||
|
||||
move( _x, _y );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
impulseEditor::~impulseEditor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::sinWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE);
|
||||
m_lastBtn = m_sinWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// generate a Sinus wave using static oscillator-method
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = oscillator::sinSample( i /
|
||||
static_cast<float>( m_sampleLength ) );
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::triangleWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE);
|
||||
m_lastBtn = m_triangleWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// generate a Triangle wave using static oscillator-method
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = oscillator::triangleSample( i /
|
||||
static_cast<float>( m_sampleLength ) );
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::sawWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE);
|
||||
m_lastBtn = m_sawWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// generate a Saw wave using static oscillator-method
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = oscillator::sawSample( i /
|
||||
static_cast<float>( m_sampleLength ) );
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::sqrWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE);
|
||||
m_lastBtn = m_sqrWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// generate a Sqr wave using static oscillator-method
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = oscillator::squareSample( i /
|
||||
static_cast<float>( m_sampleLength ) );
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::noiseWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE);
|
||||
m_lastBtn = m_whiteNoiseWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// generate a Noise wave using static oscillator-method
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = oscillator::noiseSample( i /
|
||||
static_cast<float>( m_sampleLength ) );
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::usrWaveClicked( void )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE );
|
||||
m_lastBtn = m_usrWaveBtn;
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
// zero sample_shape
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = 0;
|
||||
}
|
||||
|
||||
// load user shape
|
||||
sampleBuffer buffer;
|
||||
QString af = buffer.openAudioFile();
|
||||
if( af != "" )
|
||||
{
|
||||
buffer.setAudioFile( af );
|
||||
|
||||
// copy buffer data
|
||||
if( m_sampleLength < static_cast<Uint32>( buffer.frames() ) )
|
||||
{
|
||||
m_sampleLength = m_sampleLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sampleLength = static_cast<int>( buffer.frames() );
|
||||
}
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = static_cast<float>(
|
||||
buffer.data()[0][i] );
|
||||
}
|
||||
}
|
||||
|
||||
sampleChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::smoothClicked( void )
|
||||
{
|
||||
m_smoothBtn->setChecked( TRUE );
|
||||
m_smoothBtn->update();
|
||||
|
||||
float* temp = new float[m_sampleLength];
|
||||
memcpy( temp, m_sampleShape, sizeof( float ) * m_sampleLength );
|
||||
|
||||
// Smoothing
|
||||
m_sampleShape[0] = temp[0] / 2.0f;
|
||||
for( Uint32 i = 1; i < m_sampleLength - 1; i++ )
|
||||
{
|
||||
m_sampleShape[i] = ( temp[i - 1] +
|
||||
temp[i] +
|
||||
temp[i + 1] ) / 3.0f;
|
||||
}
|
||||
m_sampleShape[m_sampleLength - 1] = temp[m_sampleLength - 1] / 2.0f;
|
||||
m_forward = FALSE;
|
||||
|
||||
// Clean up
|
||||
delete[] temp;
|
||||
|
||||
// paint
|
||||
update();
|
||||
m_graph->update();
|
||||
|
||||
engine::getSongEditor()->setModified();
|
||||
|
||||
m_smoothBtn->setChecked( FALSE );
|
||||
m_smoothBtn->update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::normalizeClicked( void )
|
||||
{
|
||||
m_normalizeBtn->setChecked( TRUE );
|
||||
m_normalizeBtn->update();
|
||||
|
||||
float max = 0.0001f;
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f )
|
||||
{
|
||||
max = fabs( m_sampleShape[i] );
|
||||
}
|
||||
}
|
||||
m_normalizeFactor = max;
|
||||
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] /= m_normalizeFactor;
|
||||
}
|
||||
|
||||
update();
|
||||
m_graph->update();
|
||||
|
||||
engine::getSongEditor()->setModified();
|
||||
|
||||
m_normalizeBtn->setChecked( FALSE );
|
||||
m_normalizeBtn->update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::sampleChanged()
|
||||
{
|
||||
// analyze
|
||||
float max = 0.0001f;
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f )
|
||||
{
|
||||
max = fabs( m_sampleShape[i] );
|
||||
}
|
||||
}
|
||||
m_normalizeFactor = max;
|
||||
|
||||
// update
|
||||
if( m_graph != NULL )
|
||||
{
|
||||
m_graph->update();
|
||||
}
|
||||
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::setOn( bool _on )
|
||||
{
|
||||
if( _on )
|
||||
{
|
||||
m_state->setChecked( TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state->setChecked( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::contextMenuEvent( QContextMenuEvent * )
|
||||
{
|
||||
captionMenu contextMenu( accessibleName() );
|
||||
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
|
||||
this, SLOT( displayHelp() ) );
|
||||
contextMenu.exec( QCursor::pos() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void impulseEditor::displayHelp( void )
|
||||
{
|
||||
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
|
||||
whatsThis() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FASTCALL impulseEditor::setValues( float * _shape )
|
||||
{
|
||||
for( Uint32 i = 0; i < m_sampleLength; i++ )
|
||||
{
|
||||
m_sampleShape[i] = _shape[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "impulse_editor.moc"
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* impulse_editor.cpp - graphic waveform editor
|
||||
*
|
||||
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
|
||||
*
|
||||
* 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 _IMPULSE_EDITOR_H
|
||||
#define _IMPULSE_EDITOR_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QCursor>
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "graph.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "led_checkbox.h"
|
||||
|
||||
|
||||
class impulseEditor: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
impulseEditor( QWidget *parent, int _x, int _y, track * _track,
|
||||
Uint32 _len = 128 );
|
||||
~impulseEditor();
|
||||
|
||||
inline float * getValues() { return( m_sampleShape ); };
|
||||
inline bool isOn() { return( m_state->isChecked() ); };
|
||||
|
||||
void FASTCALL setValues( float * _shape );
|
||||
|
||||
public slots:
|
||||
void sinWaveClicked( void );
|
||||
void triangleWaveClicked( void );
|
||||
void sawWaveClicked( void );
|
||||
void sqrWaveClicked( void );
|
||||
void noiseWaveClicked( void );
|
||||
void usrWaveClicked( void );
|
||||
void smoothClicked( void );
|
||||
void normalizeClicked( void );
|
||||
void sampleChanged();
|
||||
void setOn( bool _on );
|
||||
void contextMenuEvent( QContextMenuEvent * );
|
||||
void displayHelp( void );
|
||||
|
||||
private:
|
||||
|
||||
graph * m_graph;
|
||||
pixmapButton * m_sinWaveBtn;
|
||||
pixmapButton * m_triangleWaveBtn;
|
||||
pixmapButton * m_sqrWaveBtn;
|
||||
pixmapButton * m_sawWaveBtn;
|
||||
pixmapButton * m_whiteNoiseWaveBtn;
|
||||
pixmapButton * m_usrWaveBtn;
|
||||
pixmapButton * m_smoothBtn;
|
||||
pixmapButton * m_normalizeBtn;
|
||||
pixmapButton * m_lastBtn;
|
||||
ledCheckBox * m_state;
|
||||
|
||||
float * m_sampleShape;
|
||||
|
||||
Uint32 m_sampleLength;
|
||||
float m_normalizeFactor;
|
||||
bool m_forward;
|
||||
|
||||
QPixmap m_base;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -51,10 +51,9 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
QPixmap _button8_off,
|
||||
Uint8 _default,
|
||||
Uint32 _x, Uint32 _y,
|
||||
QWidget * _parent,
|
||||
track * _track ):
|
||||
QWidget * _parent ):
|
||||
QWidget( _parent ),
|
||||
m_selected( _default )
|
||||
autoModelView( new nineButtonSelectorModel(0, 8, _default, 1, NULL, TRUE ) )
|
||||
{
|
||||
setFixedSize( 50, 50 );
|
||||
m_base = QPixmap::grabWidget( _parent, _x, _y );
|
||||
@@ -65,7 +64,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
pal.setBrush( backgroundRole(), m_base );
|
||||
setPalette( pal );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 1, 1 );
|
||||
m_button->setActiveGraphic( _button0_on );
|
||||
m_button->setInactiveGraphic( _button0_off );
|
||||
@@ -74,7 +73,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button0Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 18, 1 );
|
||||
m_button->setActiveGraphic( _button1_on );
|
||||
m_button->setInactiveGraphic( _button1_off );
|
||||
@@ -83,7 +82,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button1Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 35, 1 );
|
||||
m_button->setActiveGraphic( _button2_on );
|
||||
m_button->setInactiveGraphic( _button2_off );
|
||||
@@ -92,7 +91,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button2Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 1, 18 );
|
||||
m_button->setActiveGraphic( _button3_on );
|
||||
m_button->setInactiveGraphic( _button3_off );
|
||||
@@ -101,7 +100,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button3Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 18, 18 );
|
||||
m_button->setActiveGraphic( _button4_on );
|
||||
m_button->setInactiveGraphic( _button4_off );
|
||||
@@ -110,7 +109,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button4Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 35, 18 );
|
||||
m_button->setActiveGraphic( _button5_on );
|
||||
m_button->setInactiveGraphic( _button5_off );
|
||||
@@ -119,7 +118,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button5Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 1, 35 );
|
||||
m_button->setActiveGraphic( _button6_on );
|
||||
m_button->setInactiveGraphic( _button6_off );
|
||||
@@ -128,7 +127,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button6Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 18, 35 );
|
||||
m_button->setActiveGraphic( _button7_on );
|
||||
m_button->setInactiveGraphic( _button7_off );
|
||||
@@ -137,7 +136,7 @@ nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
|
||||
this, SLOT ( button7Clicked( void ) ) );
|
||||
m_buttons.append( m_button );
|
||||
|
||||
m_button = new pixmapButton( this, NULL, _track );
|
||||
m_button = new pixmapButton( this, NULL );
|
||||
m_button->move( 35, 35 );
|
||||
m_button->setActiveGraphic( _button8_on );
|
||||
m_button->setInactiveGraphic( _button8_off );
|
||||
@@ -231,22 +230,29 @@ void nineButtonSelector::button8Clicked( void )
|
||||
setSelected( 8 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void nineButtonSelector::modelChanged( void )
|
||||
{
|
||||
printf("Model Changed %d", model()->value());
|
||||
updateButton( model()->value() );
|
||||
}
|
||||
|
||||
void FASTCALL nineButtonSelector::setSelected( Uint8 _new_button )
|
||||
{
|
||||
m_selected = _new_button;
|
||||
|
||||
m_lastBtn->setChecked( FALSE );
|
||||
m_lastBtn = m_buttons[m_selected];
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
|
||||
emit nineButtonSelection( m_selected );
|
||||
model()->setValue(_new_button);
|
||||
updateButton( _new_button );
|
||||
}
|
||||
|
||||
void FASTCALL nineButtonSelector::updateButton( Uint8 _new_button )
|
||||
{
|
||||
m_lastBtn->setChecked( FALSE );
|
||||
m_lastBtn->update();
|
||||
|
||||
|
||||
m_lastBtn = m_buttons[_new_button];
|
||||
m_lastBtn->setChecked( TRUE );
|
||||
m_lastBtn->update();
|
||||
|
||||
emit nineButtonSelection( _new_button );
|
||||
}
|
||||
|
||||
void nineButtonSelector::contextMenuEvent( QContextMenuEvent * )
|
||||
{
|
||||
|
||||
@@ -29,12 +29,14 @@
|
||||
#include "pixmap_button.h"
|
||||
|
||||
|
||||
class nineButtonSelector: public QWidget
|
||||
class nineButtonSelector: public QWidget , public intModelView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
nineButtonSelector( QPixmap _button1_on,
|
||||
nineButtonSelector( QPixmap _button0_on,
|
||||
QPixmap _button0_off,
|
||||
QPixmap _button1_on,
|
||||
QPixmap _button1_off,
|
||||
QPixmap _button2_on,
|
||||
QPixmap _button2_off,
|
||||
@@ -50,15 +52,16 @@ public:
|
||||
QPixmap _button7_off,
|
||||
QPixmap _button8_on,
|
||||
QPixmap _button8_off,
|
||||
QPixmap _button9_on,
|
||||
QPixmap _button9_off,
|
||||
Uint8 _default,
|
||||
Uint32 _x, Uint32 _y,
|
||||
QWidget * _parent,
|
||||
track * _track );
|
||||
QWidget * _parent);
|
||||
~nineButtonSelector();
|
||||
|
||||
inline Uint8 getSelected() { return( m_selected ); };
|
||||
// inline Uint8 getSelected() {
|
||||
// return( castModel<nineButtonSelectorModel>()->value() );
|
||||
// };
|
||||
|
||||
protected:
|
||||
void FASTCALL setSelected( Uint8 _new_button );
|
||||
|
||||
public slots:
|
||||
@@ -78,11 +81,18 @@ signals:
|
||||
void nineButtonSelection( Uint8 );
|
||||
|
||||
private:
|
||||
virtual void modelChanged( void );
|
||||
void updateButton( Uint8 );
|
||||
|
||||
QList<pixmapButton *> m_buttons;
|
||||
pixmapButton * m_button;
|
||||
pixmapButton * m_lastBtn;
|
||||
QPixmap m_base;
|
||||
|
||||
|
||||
Uint8 m_selected;
|
||||
|
||||
};
|
||||
|
||||
typedef nineButtonSelector::autoModel nineButtonSelectorModel;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,7 +45,7 @@ stringContainer::stringContainer(const float _pitch,
|
||||
void stringContainer::addString(Uint8 _harm,
|
||||
const float _pick,
|
||||
const float _pickup,
|
||||
float * _impluse,
|
||||
const float * _impulse,
|
||||
const float _randomize,
|
||||
const float _string_loss,
|
||||
const float _detune,
|
||||
@@ -90,7 +90,7 @@ void stringContainer::addString(Uint8 _harm,
|
||||
m_strings.append( new vibratingString( m_pitch * harm,
|
||||
_pick,
|
||||
_pickup,
|
||||
_impluse,
|
||||
const_cast<float*>(_impulse),
|
||||
m_bufferLength,
|
||||
m_sampleRate,
|
||||
_oversample,
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void addString( Uint8 _harm,
|
||||
const float _pick,
|
||||
const float _pickup,
|
||||
float * _impluse,
|
||||
const float * _impluse,
|
||||
const float _randomize,
|
||||
const float _string_loss,
|
||||
const float _detune,
|
||||
|
||||
@@ -23,22 +23,22 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "vibed.h"
|
||||
|
||||
#include <Qt/QtXml>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtGui/QWhatsThis>
|
||||
|
||||
#include "base64.h"
|
||||
#include "caption_menu.h"
|
||||
#include "vibed.h"
|
||||
#include "automatable_model_templates.h"
|
||||
|
||||
#include "engine.h"
|
||||
#include "instrument_track.h"
|
||||
#include "knob.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "tooltip.h"
|
||||
#include "base64.h"
|
||||
#include "caption_menu.h"
|
||||
#include "oscillator.h"
|
||||
#include "string_container.h"
|
||||
#include "templates.h"
|
||||
#include "tooltip.h"
|
||||
#include "volume.h"
|
||||
#include "volume_knob.h"
|
||||
|
||||
@@ -48,13 +48,13 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
||||
plugin::descriptor vibedstrings_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"Vibed",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"Vibrating string modeler" ),
|
||||
"Vibrating string modeler" ),
|
||||
"Danny McRae <khjklujn/at/yahoo/com>",
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
@@ -66,258 +66,58 @@ plugin::descriptor vibedstrings_plugin_descriptor =
|
||||
|
||||
|
||||
vibed::vibed( instrumentTrack * instrument_track ) :
|
||||
instrument( instrument_track, &vibedstrings_plugin_descriptor ),
|
||||
m_sampleLength( 128 )
|
||||
instrument( instrument_track, &vibedstrings_plugin_descriptor )
|
||||
{
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
|
||||
knobModel * knob;
|
||||
boolModel * led;
|
||||
nineButtonSelectorModel * harmonic;
|
||||
graphModel * graphTmp;
|
||||
|
||||
for( Uint8 harm = 0; harm < 9; harm++ )
|
||||
{
|
||||
m_editor = new impulseEditor( this, 76, 21, instrument_track );
|
||||
m_editor->setAccessibleName( tr( "Impulse Editor" ) );
|
||||
m_editor->setOn( FALSE );
|
||||
m_editor->hide();
|
||||
m_editors.append( m_editor );
|
||||
m_editor->setWhatsThis( tr(
|
||||
"The waveform editor provides control over the initial state or impulse "
|
||||
"that is used to start the string vibrating. The buttons to the right of "
|
||||
"the graph will initialize the waveform to the selected type. The '?' "
|
||||
"button will load a waveform from a file--only the first 128 samples "
|
||||
"will be loaded.\n\n"
|
||||
knob = new knobModel( DEFAULT_VOLUME, MIN_VOLUME, MAX_VOLUME, 1.0f, this );
|
||||
m_volumeKnobs.append( knob );
|
||||
|
||||
"The waveform can also be drawn in the graph.\n\n"
|
||||
knob = new knobModel( 0.0f, 0.0f, 0.05f, 0.001f, this );
|
||||
m_stiffnessKnobs.append( knob );
|
||||
|
||||
"The 'S' button will smooth the waveform.\n\n"
|
||||
knob = new knobModel( 0.0f, 0.0f, 0.05f, 0.001f, this );
|
||||
m_stiffnessKnobs.append( knob );
|
||||
|
||||
"The 'N' button will normalize the waveform.") );
|
||||
knob = new knobModel( 0.0f, 0.0f, 0.05f, 0.005f, this );
|
||||
m_pickKnobs.append( knob );
|
||||
|
||||
m_volumeKnob = new volumeKnob( knobBright_26, this,
|
||||
tr( "Volume" ), instrument_track );
|
||||
m_volumeKnob->setRange( MIN_VOLUME, MAX_VOLUME, 1.0f );
|
||||
m_volumeKnob->setInitValue( DEFAULT_VOLUME );
|
||||
m_volumeKnob->move( 103, 142 );
|
||||
m_volumeKnob->setHintText( tr( "Volume:" ) + " ", "" );
|
||||
m_volumeKnob->hide();
|
||||
m_volumeKnobs.append( m_volumeKnob );
|
||||
m_volumeKnob->setWhatsThis( tr( "The 'V' knob sets the volume "
|
||||
"of the selected string." ) );
|
||||
|
||||
m_stiffnessKnob = new knob( knobBright_26, this,
|
||||
tr( "String stiffness" ),
|
||||
instrument_track );
|
||||
m_stiffnessKnob->setRange( 0.0f, 0.05f, 0.001f );
|
||||
m_stiffnessKnob->setInitValue( 0.0f );
|
||||
m_stiffnessKnob->move( 129, 142 );
|
||||
m_stiffnessKnob->setHintText( tr( "String stiffness:" ) +
|
||||
" ", "" );
|
||||
m_stiffnessKnob->hide();
|
||||
m_stiffnessKnobs.append( m_stiffnessKnob );
|
||||
m_stiffnessKnob->setWhatsThis( tr(
|
||||
"The 'S' knob sets the stiffness of the selected string. The stiffness "
|
||||
"of the string affects how long the string will ring out. The lower "
|
||||
"the setting, the longer the string will ring." ) );
|
||||
|
||||
|
||||
m_pickKnob = new knob( knobBright_26, this,
|
||||
tr( "Pick position" ),
|
||||
instrument_track );
|
||||
m_pickKnob->setRange( 0.0f, 0.5f, 0.005f );
|
||||
m_pickKnob->setInitValue( 0.0f );
|
||||
m_pickKnob->move( 153, 142 );
|
||||
m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" );
|
||||
m_pickKnob->hide();
|
||||
m_pickKnobs.append( m_pickKnob );
|
||||
m_pickKnob->setWhatsThis( tr(
|
||||
"The 'P' knob sets the position where the selected string will be 'picked'. "
|
||||
"The lower the setting the closer the pick is to the bridge." ) );
|
||||
|
||||
m_pickupKnob = new knob( knobBright_26, this,
|
||||
tr( "Pickup position" ),
|
||||
instrument_track );
|
||||
m_pickupKnob->setRange( 0.0f, 0.5f, 0.005f );
|
||||
m_pickupKnob->setInitValue( 0.05f );
|
||||
m_pickupKnob->move( 177, 142 );
|
||||
m_pickupKnob->setHintText( tr( "Pickup position:" ) +
|
||||
" ", "" );
|
||||
m_pickupKnob->hide();
|
||||
m_pickupKnobs.append( m_pickupKnob );
|
||||
m_pickupKnob->setWhatsThis( tr(
|
||||
"The 'PU' knob sets the position where the vibrations will be monitored "
|
||||
"for the selected string. The lower the setting, the closer the "
|
||||
"pickup is to the bridge." ) );
|
||||
knob = new knobModel( 0.05f, 0.0f, 0.05f, 0.005f, this );
|
||||
m_pickupKnobs.append( knob );
|
||||
|
||||
m_panKnob = new knob( knobBright_26, this, tr( "Pan" ),
|
||||
instrument_track );
|
||||
m_panKnob->setRange( -1.0f, 1.0f, 0.01f );
|
||||
m_panKnob->setInitValue( 0.0f );
|
||||
m_panKnob->move( 105, 187 );
|
||||
m_panKnob->setHintText( tr( "Pan:" ) + " ", "" );
|
||||
m_panKnob->hide();
|
||||
m_panKnobs.append( m_panKnob );
|
||||
m_panKnob->setWhatsThis( tr(
|
||||
"The Pan knob determines the location of the selected string in the stereo "
|
||||
"field." ) );
|
||||
|
||||
m_detuneKnob = new knob( knobBright_26, this, tr( "Detune" ),
|
||||
instrument_track );
|
||||
m_detuneKnob->setRange( -0.1f, 0.1f, 0.001f );
|
||||
m_detuneKnob->setInitValue( 0.0f );
|
||||
m_detuneKnob->move( 150, 187 );
|
||||
m_detuneKnob->setHintText( tr( "Detune:" ) + " ", "" );
|
||||
m_detuneKnob->hide();
|
||||
m_detuneKnobs.append( m_detuneKnob );
|
||||
m_detuneKnob->setWhatsThis( tr(
|
||||
"The Detune knob modifies the pitch of the selected string. Settings less "
|
||||
"than zero will cause the string to sound flat. Settings greater than zero "
|
||||
"will cause the string to sound sharp." ) );
|
||||
|
||||
m_randomKnob = new knob( knobBright_26, this, tr( "Fuzziness" ),
|
||||
instrument_track );
|
||||
m_randomKnob->setRange( 0.0f, 0.75f, 0.01f );
|
||||
m_randomKnob->setInitValue( 0.0f );
|
||||
m_randomKnob->move( 194, 187 );
|
||||
m_randomKnob->setHintText( tr( "Fuzziness:" ) +
|
||||
" ", "" );
|
||||
m_randomKnob->hide();
|
||||
m_randomKnobs.append( m_randomKnob );
|
||||
m_randomKnob->setWhatsThis( tr(
|
||||
"The Slap knob adds a bit of fuzz to the selected string which is most "
|
||||
"apparent during the attack, though it can also be used to make the string "
|
||||
"sound more 'metallic'.") );
|
||||
knob = new knobModel( 0.0f, -1.0f, 1.0f, 0.01f, this );
|
||||
m_panKnobs.append( knob );
|
||||
|
||||
m_lengthKnob = new knob( knobBright_26, this, tr( "Length" ),
|
||||
instrument_track );
|
||||
m_lengthKnob->setRange( 1, 16, 1 );
|
||||
m_lengthKnob->setInitValue( 1 );
|
||||
m_lengthKnob->move( 23, 193 );
|
||||
m_lengthKnob->setHintText( tr( "Length:" ) +
|
||||
" ", "" );
|
||||
m_lengthKnob->hide();
|
||||
m_lengthKnobs.append( m_lengthKnob );
|
||||
m_lengthKnob->setWhatsThis( tr(
|
||||
"The Length knob sets the length of the selected string. Longer strings "
|
||||
"will both ring longer and sound brighter, however, they will also eat up "
|
||||
"more CPU cycles." ) );
|
||||
knob = new knobModel( 0.0f, -0.1f, 0.1f, 0.001f, this );
|
||||
m_detuneKnobs.append( knob );
|
||||
|
||||
m_impulse = new ledCheckBox( "", this, tr( "Impulse" ),
|
||||
instrument_track );
|
||||
m_impulse->move( 23, 94 );
|
||||
m_impulse->setChecked( FALSE );
|
||||
toolTip::add( m_impulse,
|
||||
tr( "Impulse or initial state" ) );
|
||||
m_impulse->hide();
|
||||
m_impulses.append( m_impulse );
|
||||
m_impulse->setWhatsThis( tr(
|
||||
"The 'Imp' selector determines whether the waveform in the graph is to be "
|
||||
"treated as an impulse imparted to the string by the pick or the initial "
|
||||
"state of the string." ) );
|
||||
knob = new knobModel( 0.0f, 0.0f, 0.75f, 0.01f, this );
|
||||
m_randomKnobs.append( knob );
|
||||
|
||||
knob = new knobModel( 1, 1, 16, 1, this );
|
||||
m_lengthKnobs.append( knob );
|
||||
|
||||
led = new boolModel( FALSE, this );
|
||||
m_impulses.append( led );
|
||||
|
||||
led = new boolModel( harm==0, this );
|
||||
m_powerButtons.append( led );
|
||||
|
||||
harmonic = new nineButtonSelectorModel( 2, 0, 8, 1, this );
|
||||
m_harmonics.append( harmonic );
|
||||
|
||||
graphTmp = new graphModel( -1.0, 1.0, m_sampleLength, this );
|
||||
graphTmp->setWaveToSine();
|
||||
|
||||
m_graphs.append( graphTmp );
|
||||
|
||||
m_harmonic = new nineButtonSelector(
|
||||
PLUGIN_NAME::getIconPixmap( "button_-2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-1_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-1_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_f_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_f_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
|
||||
2,
|
||||
21, 127,
|
||||
this,
|
||||
NULL );
|
||||
m_harmonic->setAccessibleName( tr( "Octave" ) );
|
||||
m_harmonic->hide();
|
||||
m_harmonics.append( m_harmonic );
|
||||
m_harmonic->setWhatsThis( tr(
|
||||
"The Octave selector is used to choose which harmonic of the note the "
|
||||
"string will ring at. For example, '-2' means the string will ring two "
|
||||
"octaves below the fundamental, 'F' means the string will ring at the "
|
||||
"fundamental, and '6' means the string will ring six octaves above the "
|
||||
"fundamental." ) );
|
||||
}
|
||||
|
||||
m_stringSelector = new nineButtonSelector(
|
||||
PLUGIN_NAME::getIconPixmap( "button_1_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_1_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_8_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_8_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_9_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_9_off" ),
|
||||
0,
|
||||
21, 39,
|
||||
this,
|
||||
NULL );
|
||||
m_stringSelector->setAccessibleName( tr( "String" ) );
|
||||
connect( m_stringSelector, SIGNAL( nineButtonSelection( Uint8 ) ),
|
||||
this, SLOT( showString( Uint8 ) ) );
|
||||
m_stringSelector->setWhatsThis( tr(
|
||||
"The String selector is used to choose which string the controls are "
|
||||
"editting. A Vibed instrument can contain up to nine independently "
|
||||
"vibrating strings. The LED in the lower right corner of the "
|
||||
"waveform editor indicates whether the selected string is active." ) );
|
||||
|
||||
m_pickKnob = m_pickKnobs[0];
|
||||
m_pickupKnob = m_pickupKnobs[0];
|
||||
m_stiffnessKnob = m_stiffnessKnobs[0];
|
||||
m_volumeKnob = m_volumeKnobs[0];
|
||||
m_panKnob = m_panKnobs[0];
|
||||
m_detuneKnob = m_detuneKnobs[0];
|
||||
m_randomKnob = m_randomKnobs[0];
|
||||
m_lengthKnob = m_lengthKnobs[0];
|
||||
m_editor = m_editors[0];
|
||||
m_impulse = m_impulses[0];
|
||||
m_harmonic = m_harmonics[0];
|
||||
|
||||
m_editor->setOn( TRUE );
|
||||
showString( 0 );
|
||||
|
||||
setWhatsThis( tr(
|
||||
"Vibed models up to nine independently vibrating strings. The 'String' "
|
||||
"selector allows you to choose which string is being edited. The 'Imp' " "selector chooses whether the graph represents an impulse or the initial "
|
||||
"state of the string. The 'Octave' selector chooses which harmonic the "
|
||||
"string should vibrate at.\n\n"
|
||||
|
||||
"The graph allows you to control the initial state or impulse used to set the "
|
||||
"string in motion.\n\n"
|
||||
|
||||
"The 'V' knob controls the volume. The 'S' knob controls the string's "
|
||||
"stiffness. The 'P' knob controls the pick position. The 'PU' knob "
|
||||
"controls the pickup position.\n\n"
|
||||
|
||||
"'Pan' and 'Detune' hopefully don't need explanation. The 'Slap' knob "
|
||||
"adds a bit of fuzz to the sound of the string.\n\n"
|
||||
|
||||
"The 'Length' knob controls the length of the string.\n\n"
|
||||
|
||||
"The LED in the lower right corner of the waveform editor determines "
|
||||
"whether the string is active in the current instrument." ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -333,6 +133,7 @@ vibed::~vibed()
|
||||
void vibed::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
|
||||
QString name;
|
||||
|
||||
// Save plugin version
|
||||
@@ -341,9 +142,10 @@ void vibed::saveSettings( QDomDocument & _doc,
|
||||
for( Uint8 i = 0; i < 9; i++ )
|
||||
{
|
||||
name = "active" + QString::number( i );
|
||||
_this.setAttribute( name, QString::number(
|
||||
m_editors[i]->isOn() ) );
|
||||
if( m_editors[i]->isOn() )
|
||||
_this.setAttribute( name, QString::number(
|
||||
m_powerButtons[i]->value() ) );
|
||||
|
||||
if( m_powerButtons[i]->value() )
|
||||
{
|
||||
name = "volume" + QString::number( i );
|
||||
m_volumeKnobs[i]->saveSettings( _doc, _this, name );
|
||||
@@ -358,8 +160,7 @@ void vibed::saveSettings( QDomDocument & _doc,
|
||||
m_pickupKnobs[i]->saveSettings( _doc, _this, name );
|
||||
|
||||
name = "octave" + QString::number( i );
|
||||
_this.setAttribute( name, QString::number(
|
||||
m_harmonics[i]->getSelected() ) );
|
||||
m_harmonics[i]->saveSettings( _doc, _this, name );
|
||||
|
||||
name = "length" + QString::number( i );
|
||||
m_lengthKnobs[i]->saveSettings( _doc, _this, name );
|
||||
@@ -375,13 +176,14 @@ void vibed::saveSettings( QDomDocument & _doc,
|
||||
|
||||
name = "impulse" + QString::number( i );
|
||||
m_impulses[i]->saveSettings( _doc, _this, name );
|
||||
|
||||
|
||||
QString sampleString;
|
||||
base64::encode(
|
||||
(const char *)m_editors[i]->getValues(),
|
||||
128 * sizeof(float), sampleString );
|
||||
base64::encode(
|
||||
(const char *)m_graphs[i]->samples(),
|
||||
m_sampleLength * sizeof(float),
|
||||
sampleString );
|
||||
name = "graph" + QString::number( i );
|
||||
_this.setAttribute( name, sampleString );
|
||||
_this.setAttribute( name, sampleString );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,17 +191,17 @@ void vibed::saveSettings( QDomDocument & _doc,
|
||||
|
||||
|
||||
|
||||
|
||||
void vibed::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
|
||||
QString name;
|
||||
|
||||
|
||||
for( Uint8 i = 0; i < 9; i++ )
|
||||
{
|
||||
name = "active" + QString::number( i );
|
||||
m_editors[i]->setOn( _this.attribute( name ).toInt() );
|
||||
m_powerButtons[i]->setValue( _this.attribute( name ).toInt() );
|
||||
|
||||
if( m_editors[i]->isOn() &&
|
||||
if( m_powerButtons[i]->value() &&
|
||||
_this.hasAttribute( "volume" + QString::number( i ) ) )
|
||||
{
|
||||
name = "volume" + QString::number( i );
|
||||
@@ -415,8 +217,7 @@ void vibed::loadSettings( const QDomElement & _this )
|
||||
m_pickupKnobs[i]->loadSettings( _this, name );
|
||||
|
||||
name = "octave" + QString::number( i );
|
||||
m_harmonics[i]->setSelected(
|
||||
_this.attribute( name ).toInt() );
|
||||
m_harmonics[i]->loadSettings( _this, name );
|
||||
|
||||
name = "length" + QString::number( i );
|
||||
m_lengthKnobs[i]->loadSettings( _this, name );
|
||||
@@ -437,11 +238,13 @@ void vibed::loadSettings( const QDomElement & _this )
|
||||
float * shp = 0;
|
||||
base64::decode( _this.attribute( "graph" +
|
||||
QString::number( i ) ),
|
||||
(char * *) &shp, &size );
|
||||
(char * *) &shp,
|
||||
&size );
|
||||
// TODO: check whether size == 128 * sizeof( float ),
|
||||
// otherwise me might and up in a segfault
|
||||
m_editors[i]->setValues( shp );
|
||||
m_graphs[i]->setSamples( shp );
|
||||
delete[] shp;
|
||||
|
||||
|
||||
// TODO: do one of the following to avoid
|
||||
// "uninitialized" wave-shape-buttongroup
|
||||
@@ -452,7 +255,7 @@ void vibed::loadSettings( const QDomElement & _this )
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
// update();
|
||||
}
|
||||
|
||||
|
||||
@@ -471,25 +274,25 @@ void vibed::playNote( notePlayHandle * _n, bool )
|
||||
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL )
|
||||
{
|
||||
_n->m_pluginData = new stringContainer( _n->frequency(),
|
||||
engine::getMixer()->sampleRate(),
|
||||
m_sampleLength );
|
||||
engine::getMixer()->sampleRate(),
|
||||
m_sampleLength );
|
||||
|
||||
for( Uint8 i = 0; i < 9; ++i )
|
||||
{
|
||||
if( m_editors[i]->isOn() )
|
||||
if( m_powerButtons[i]->value() )
|
||||
{
|
||||
static_cast<stringContainer*>(
|
||||
_n->m_pluginData )->addString(
|
||||
m_harmonics[i]->getSelected(),
|
||||
m_harmonics[i]->value(),
|
||||
m_pickKnobs[i]->value(),
|
||||
m_pickupKnobs[i]->value(),
|
||||
m_editors[i]->getValues(),
|
||||
m_graphs[i]->samples(),
|
||||
m_randomKnobs[i]->value(),
|
||||
m_stiffnessKnobs[i]->value(),
|
||||
m_detuneKnobs[i]->value(),
|
||||
static_cast<int>(
|
||||
m_lengthKnobs[i]->value() ),
|
||||
m_impulses[i]->isChecked(),
|
||||
m_impulses[i]->value(),
|
||||
i );
|
||||
}
|
||||
}
|
||||
@@ -497,8 +300,8 @@ void vibed::playNote( notePlayHandle * _n, bool )
|
||||
|
||||
const fpp_t frames = _n->framesLeftForCurrentPeriod();
|
||||
stringContainer * ps = static_cast<stringContainer *>(
|
||||
_n->m_pluginData );
|
||||
|
||||
_n->m_pluginData );
|
||||
|
||||
sampleFrame * buf = new sampleFrame[frames];
|
||||
|
||||
for( fpp_t i = 0; i < frames; ++i )
|
||||
@@ -538,77 +341,421 @@ void vibed::deleteNotePluginData( notePlayHandle * _n )
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vibed::showString( Uint8 _string )
|
||||
pluginView * vibed::instantiateView( QWidget * _parent )
|
||||
{
|
||||
m_pickKnob->hide();
|
||||
m_pickupKnob->hide();
|
||||
m_stiffnessKnob->hide();
|
||||
m_volumeKnob->hide();
|
||||
m_panKnob->hide();
|
||||
m_detuneKnob->hide();
|
||||
m_randomKnob->hide();
|
||||
m_lengthKnob->hide();
|
||||
m_editor->hide();
|
||||
m_impulse->hide();
|
||||
m_harmonic->hide();
|
||||
|
||||
// TODO: first assign, then show - avoids that we have to index vector
|
||||
// (or list or whatever) twice
|
||||
// something like
|
||||
// ( m_editor = m_editors[_string] )->show()
|
||||
// would be even better ;-)
|
||||
m_editors[_string]->show();
|
||||
m_volumeKnobs[_string]->show();
|
||||
m_stiffnessKnobs[_string]->show();
|
||||
m_pickKnobs[_string]->show();
|
||||
m_pickupKnobs[_string]->show();
|
||||
m_panKnobs[_string]->show();
|
||||
m_detuneKnobs[_string]->show();
|
||||
m_randomKnobs[_string]->show();
|
||||
m_lengthKnobs[_string]->show();
|
||||
m_impulses[_string]->show();
|
||||
m_impulses[_string]->update();
|
||||
m_harmonics[_string]->show();
|
||||
|
||||
m_pickKnob = m_pickKnobs[_string];
|
||||
m_pickupKnob = m_pickupKnobs[_string];
|
||||
m_stiffnessKnob = m_stiffnessKnobs[_string];
|
||||
m_volumeKnob = m_volumeKnobs[_string];
|
||||
m_panKnob = m_panKnobs[_string];
|
||||
m_detuneKnob = m_detuneKnobs[_string];
|
||||
m_randomKnob = m_randomKnobs[_string];
|
||||
m_lengthKnob = m_lengthKnobs[_string];
|
||||
m_editor = m_editors[_string];
|
||||
m_impulse = m_impulses[_string];
|
||||
m_harmonic = m_harmonics[_string];
|
||||
return( new vibedView( this, _parent ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void vibed::contextMenuEvent( QContextMenuEvent * )
|
||||
vibedView::vibedView( instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
instrumentView( _instrument, _parent )
|
||||
{
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
|
||||
m_volumeKnob = new volumeKnob( knobBright_26, this, tr( "Volume" ) );
|
||||
m_volumeKnob->move( 103, 142 );
|
||||
m_volumeKnob->setHintText( tr( "Volume:" ) + " ", "" );
|
||||
m_volumeKnob->setWhatsThis( tr( "The 'V' knob sets the volume "
|
||||
"of the selected string." ) );
|
||||
|
||||
m_stiffnessKnob = new knob( knobBright_26, this,
|
||||
tr( "String stiffness" ) );
|
||||
m_stiffnessKnob->move( 129, 142 );
|
||||
m_stiffnessKnob->setHintText( tr( "String stiffness:" ) +
|
||||
" ", "" );
|
||||
m_stiffnessKnob->setWhatsThis( tr(
|
||||
"The 'S' knob sets the stiffness of the selected string. The stiffness "
|
||||
"of the string affects how long the string will ring out. The lower "
|
||||
"the setting, the longer the string will ring." ) );
|
||||
|
||||
|
||||
m_pickKnob = new knob( knobBright_26, this,
|
||||
tr( "Pick position" ) );
|
||||
m_pickKnob->move( 153, 142 );
|
||||
m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" );
|
||||
m_pickKnob->setWhatsThis( tr(
|
||||
"The 'P' knob sets the position where the selected string will be 'picked'. "
|
||||
"The lower the setting the closer the pick is to the bridge." ) );
|
||||
|
||||
m_pickupKnob = new knob( knobBright_26, this,
|
||||
tr( "Pickup position" ) );
|
||||
m_pickupKnob->move( 177, 142 );
|
||||
m_pickupKnob->setHintText( tr( "Pickup position:" ) +
|
||||
" ", "" );
|
||||
m_pickupKnob->setWhatsThis( tr(
|
||||
"The 'PU' knob sets the position where the vibrations will be monitored "
|
||||
"for the selected string. The lower the setting, the closer the "
|
||||
"pickup is to the bridge." ) );
|
||||
|
||||
m_panKnob = new knob( knobBright_26, this, tr( "Pan" ) );
|
||||
m_panKnob->move( 105, 187 );
|
||||
m_panKnob->setHintText( tr( "Pan:" ) + " ", "" );
|
||||
m_panKnob->setWhatsThis( tr(
|
||||
"The Pan knob determines the location of the selected string in the stereo "
|
||||
"field." ) );
|
||||
|
||||
m_detuneKnob = new knob( knobBright_26, this, tr( "Detune" ) );
|
||||
m_detuneKnob->move( 150, 187 );
|
||||
m_detuneKnob->setHintText( tr( "Detune:" ) + " ", "" );
|
||||
m_detuneKnob->setWhatsThis( tr(
|
||||
"The Detune knob modifies the pitch of the selected string. Settings less "
|
||||
"than zero will cause the string to sound flat. Settings greater than zero "
|
||||
"will cause the string to sound sharp." ) );
|
||||
|
||||
m_randomKnob = new knob( knobBright_26, this, tr( "Fuzziness" ) );
|
||||
m_randomKnob->move( 194, 187 );
|
||||
m_randomKnob->setHintText( tr( "Fuzziness:" ) +
|
||||
" ", "" );
|
||||
m_randomKnob->setWhatsThis( tr(
|
||||
"The Slap knob adds a bit of fuzz to the selected string which is most "
|
||||
"apparent during the attack, though it can also be used to make the string "
|
||||
"sound more 'metallic'.") );
|
||||
|
||||
m_lengthKnob = new knob( knobBright_26, this, tr( "Length" ) );
|
||||
m_lengthKnob->move( 23, 193 );
|
||||
m_lengthKnob->setHintText( tr( "Length:" ) +
|
||||
" ", "" );
|
||||
m_lengthKnob->setWhatsThis( tr(
|
||||
"The Length knob sets the length of the selected string. Longer strings "
|
||||
"will both ring longer and sound brighter, however, they will also eat up "
|
||||
"more CPU cycles." ) );
|
||||
|
||||
m_impulse = new ledCheckBox( "", this, tr( "Impulse" ) );
|
||||
m_impulse->move( 23, 94 );
|
||||
toolTip::add( m_impulse,
|
||||
tr( "Impulse or initial state" ) );
|
||||
m_impulse->setWhatsThis( tr(
|
||||
"The 'Imp' selector determines whether the waveform in the graph is to be "
|
||||
"treated as an impulse imparted to the string by the pick or the initial "
|
||||
"state of the string." ) );
|
||||
|
||||
m_harmonic = new nineButtonSelector(
|
||||
PLUGIN_NAME::getIconPixmap( "button_-2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-1_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_-1_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_f_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_f_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
|
||||
2,
|
||||
21, 127,
|
||||
this );
|
||||
|
||||
m_harmonic->setAccessibleName( tr( "Octave" ) );
|
||||
m_harmonic->setWhatsThis( tr(
|
||||
"The Octave selector is used to choose which harmonic of the note the "
|
||||
"string will ring at. For example, '-2' means the string will ring two "
|
||||
"octaves below the fundamental, 'F' means the string will ring at the "
|
||||
"fundamental, and '6' means the string will ring six octaves above the "
|
||||
"fundamental." ) );
|
||||
|
||||
|
||||
m_stringSelector = new nineButtonSelector(
|
||||
PLUGIN_NAME::getIconPixmap( "button_1_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_1_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_8_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_8_off" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_9_on" ),
|
||||
PLUGIN_NAME::getIconPixmap( "button_9_off" ),
|
||||
0,
|
||||
21, 39,
|
||||
this);
|
||||
|
||||
m_graph = new graph( this );
|
||||
m_graph->setAccessibleName( tr( "Impulse Editor" ) );
|
||||
m_graph->setForeground( PLUGIN_NAME::getIconPixmap( "wavegraph4" ) );
|
||||
m_graph->move( 76, 21 );
|
||||
m_graph->resize(132, 104);
|
||||
|
||||
m_graph->setWhatsThis( tr(
|
||||
"The waveform editor provides control over the initial state or impulse "
|
||||
"that is used to start the string vibrating. The buttons to the right of "
|
||||
"the graph will initialize the waveform to the selected type. The '?' "
|
||||
"button will load a waveform from a file--only the first 128 samples "
|
||||
"will be loaded.\n\n"
|
||||
|
||||
"The waveform can also be drawn in the graph.\n\n"
|
||||
|
||||
"The 'S' button will smooth the waveform.\n\n"
|
||||
|
||||
"The 'N' button will normalize the waveform.") );
|
||||
|
||||
|
||||
setWhatsThis( tr(
|
||||
"Vibed models up to nine independently vibrating strings. The 'String' "
|
||||
"selector allows you to choose which string is being edited. The 'Imp' " "selector chooses whether the graph represents an impulse or the initial "
|
||||
"state of the string. The 'Octave' selector chooses which harmonic the "
|
||||
"string should vibrate at.\n\n"
|
||||
|
||||
"The graph allows you to control the initial state or impulse used to set the "
|
||||
"string in motion.\n\n"
|
||||
|
||||
"The 'V' knob controls the volume. The 'S' knob controls the string's "
|
||||
"stiffness. The 'P' knob controls the pick position. The 'PU' knob "
|
||||
"controls the pickup position.\n\n"
|
||||
|
||||
"'Pan' and 'Detune' hopefully don't need explanation. The 'Slap' knob "
|
||||
"adds a bit of fuzz to the sound of the string.\n\n"
|
||||
|
||||
"The 'Length' knob controls the length of the string.\n\n"
|
||||
|
||||
"The LED in the lower right corner of the waveform editor determines "
|
||||
"whether the string is active in the current instrument." ) );
|
||||
|
||||
|
||||
m_power = new ledCheckBox( "", this, tr( "Enable waveform" ) );
|
||||
m_power->move( 212, 130 );
|
||||
toolTip::add( m_power,
|
||||
tr( "Click here to enable/disable waveform." ) );
|
||||
|
||||
|
||||
// String selector is not a part of the model
|
||||
m_stringSelector->setAccessibleName( tr( "String" ) );
|
||||
m_stringSelector->setWhatsThis( tr(
|
||||
"The String selector is used to choose which string the controls are "
|
||||
"editting. A Vibed instrument can contain up to nine independently "
|
||||
"vibrating strings. The LED in the lower right corner of the "
|
||||
"waveform editor indicates whether the selected string is active." ) );
|
||||
|
||||
connect( m_stringSelector, SIGNAL( nineButtonSelection( Uint8 ) ),
|
||||
this, SLOT( showString( Uint8 ) ) );
|
||||
|
||||
showString( 0 );
|
||||
// Get current graph-model
|
||||
graphModel * gModel = m_graph->model();
|
||||
|
||||
m_sinWaveBtn = new pixmapButton( this, tr( "Sine wave" ) );
|
||||
m_sinWaveBtn->move( 212, 24 );
|
||||
m_sinWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"sin_wave_active" ) );
|
||||
m_sinWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"sin_wave_inactive" ) );
|
||||
toolTip::add( m_sinWaveBtn,
|
||||
tr( "Click here if you want a sine-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sinWaveBtn, SIGNAL (clicked ( void ) ),
|
||||
this, SLOT ( sinWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_triangleWaveBtn = new pixmapButton( this, tr( "Triangle wave" ) );
|
||||
m_triangleWaveBtn->move( 212, 41 );
|
||||
m_triangleWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap( "triangle_wave_active" ) );
|
||||
m_triangleWaveBtn->setInactiveGraphic(
|
||||
embed::getIconPixmap( "triangle_wave_inactive" ) );
|
||||
toolTip::add( m_triangleWaveBtn,
|
||||
tr( "Click here if you want a triangle-wave "
|
||||
"for current oscillator." ) );
|
||||
connect( m_triangleWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( triangleWaveClicked( ) ) );
|
||||
|
||||
|
||||
m_sawWaveBtn = new pixmapButton( this, tr( "Saw wave" ) );
|
||||
m_sawWaveBtn->move( 212, 58 );
|
||||
m_sawWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"saw_wave_active" ) );
|
||||
m_sawWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"saw_wave_inactive" ) );
|
||||
toolTip::add( m_sawWaveBtn,
|
||||
tr( "Click here if you want a saw-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sawWaveBtn, SIGNAL (clicked ( void ) ),
|
||||
this, SLOT ( sawWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_sqrWaveBtn = new pixmapButton( this, tr( "Square wave" ) );
|
||||
m_sqrWaveBtn->move( 212, 75 );
|
||||
m_sqrWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"square_wave_active" ) );
|
||||
m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"square_wave_inactive" ) );
|
||||
toolTip::add( m_sqrWaveBtn,
|
||||
tr( "Click here if you want a square-wave for "
|
||||
"current oscillator." ) );
|
||||
connect( m_sqrWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( sqrWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_whiteNoiseWaveBtn = new pixmapButton( this, tr( "White noise wave" ) );
|
||||
m_whiteNoiseWaveBtn->move( 212, 92 );
|
||||
m_whiteNoiseWaveBtn->setActiveGraphic(
|
||||
embed::getIconPixmap( "white_noise_wave_active" ) );
|
||||
m_whiteNoiseWaveBtn->setInactiveGraphic(
|
||||
embed::getIconPixmap( "white_noise_wave_inactive" ) );
|
||||
toolTip::add( m_whiteNoiseWaveBtn,
|
||||
tr( "Click here if you want a white-noise for "
|
||||
"current oscillator." ) );
|
||||
connect( m_whiteNoiseWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( noiseWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_usrWaveBtn = new pixmapButton( this, tr( "User defined wave" ) );
|
||||
m_usrWaveBtn->move( 212, 109 );
|
||||
m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap(
|
||||
"usr_wave_active" ) );
|
||||
m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
|
||||
"usr_wave_inactive" ) );
|
||||
toolTip::add( m_usrWaveBtn,
|
||||
tr( "Click here if you want a user-defined "
|
||||
"wave-shape for current oscillator." ) );
|
||||
connect( m_usrWaveBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( usrWaveClicked( void ) ) );
|
||||
|
||||
|
||||
m_smoothBtn = new pixmapButton( this, tr( "Smooth" ) );
|
||||
m_smoothBtn->move( 79, 129 );
|
||||
m_smoothBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"smooth_active" ) );
|
||||
m_smoothBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"smooth_inactive" ) );
|
||||
m_smoothBtn->setChecked( FALSE );
|
||||
toolTip::add( m_smoothBtn,
|
||||
tr( "Click here to smooth waveform." ) );
|
||||
connect( m_smoothBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( smoothClicked( void ) ) );
|
||||
|
||||
m_normalizeBtn = new pixmapButton( this, tr( "Normalize" ) );
|
||||
m_normalizeBtn->move( 96, 129 );
|
||||
m_normalizeBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"normalize_active" ) );
|
||||
m_normalizeBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"normalize_inactive" ) );
|
||||
m_normalizeBtn->setChecked( FALSE );
|
||||
toolTip::add( m_normalizeBtn,
|
||||
tr( "Click here to normalize waveform." ) );
|
||||
|
||||
connect( m_normalizeBtn, SIGNAL ( clicked ( void ) ),
|
||||
this, SLOT ( normalizeClicked( void ) ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vibedView::modelChanged( void )
|
||||
{
|
||||
showString( 0 );
|
||||
}
|
||||
|
||||
|
||||
void vibedView::showString( Uint8 _string )
|
||||
{
|
||||
vibed * v = castModel<vibed>();
|
||||
|
||||
m_pickKnob->setModel( v->m_pickKnobs[_string] );
|
||||
m_pickupKnob->setModel( v->m_pickupKnobs[_string] );
|
||||
m_stiffnessKnob->setModel( v->m_stiffnessKnobs[_string] );
|
||||
m_volumeKnob->setModel( v->m_volumeKnobs[_string] );
|
||||
m_panKnob->setModel( v->m_panKnobs[_string] );
|
||||
m_detuneKnob->setModel( v->m_detuneKnobs[_string] );
|
||||
m_randomKnob->setModel( v->m_randomKnobs[_string] );
|
||||
m_lengthKnob->setModel( v->m_lengthKnobs[_string] );
|
||||
m_graph->setModel( v->m_graphs[_string] );
|
||||
m_impulse->setModel( v->m_impulses[_string] );
|
||||
m_harmonic->setModel( v->m_harmonics[_string] );
|
||||
m_power->setModel( v->m_powerButtons[_string] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vibedView::sinWaveClicked( void )
|
||||
{
|
||||
m_graph->model()->setWaveToSine();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::triangleWaveClicked( void )
|
||||
{
|
||||
m_graph->model()->setWaveToTriangle();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::sawWaveClicked( void )
|
||||
{
|
||||
m_graph->model()->setWaveToSaw();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::sqrWaveClicked( void )
|
||||
{
|
||||
m_graph->model()->setWaveToSquare();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::noiseWaveClicked( void )
|
||||
{
|
||||
m_graph->model()->setWaveToNoise();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::usrWaveClicked( void )
|
||||
{
|
||||
// TODO: load file
|
||||
//m_graph->model()->setWaveToUser();
|
||||
//engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::smoothClicked( void )
|
||||
{
|
||||
m_graph->model()->smooth();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
void vibedView::normalizeClicked( void )
|
||||
{
|
||||
m_graph->model()->normalize();
|
||||
engine::getSongEditor()->setModified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vibedView::contextMenuEvent( QContextMenuEvent * )
|
||||
{
|
||||
|
||||
captionMenu contextMenu( publicName() );
|
||||
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
|
||||
this, SLOT( displayHelp() ) );
|
||||
this, SLOT( displayHelp() ) );
|
||||
contextMenu.exec( QCursor::pos() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vibed::displayHelp( void )
|
||||
void vibedView::displayHelp( void )
|
||||
{
|
||||
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
|
||||
whatsThis() );
|
||||
whatsThis() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
||||
@@ -24,56 +24,91 @@
|
||||
#define _VIBED_STRINGS_H
|
||||
|
||||
#include "instrument.h"
|
||||
#include "instrument_view.h"
|
||||
#include "sample_buffer.h"
|
||||
#include "graph.h"
|
||||
#include "knob.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "impulse_editor.h"
|
||||
#include "lcd_spinbox.h"
|
||||
#include "volume_knob.h"
|
||||
#include "nine_button_selector.h"
|
||||
|
||||
class knob;
|
||||
class vibedView;
|
||||
class notePlayHandle;
|
||||
class volumeKnob;
|
||||
|
||||
|
||||
class vibed : public instrument
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
vibed( instrumentTrack * _channel_track );
|
||||
virtual ~vibed();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
virtual pluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
|
||||
private:
|
||||
QList<knobModel*> m_pickKnobs;
|
||||
QList<knobModel*> m_pickupKnobs;
|
||||
QList<knobModel*> m_stiffnessKnobs;
|
||||
QList<knobModel*> m_volumeKnobs;
|
||||
QList<knobModel*> m_panKnobs;
|
||||
QList<knobModel*> m_detuneKnobs;
|
||||
QList<knobModel*> m_randomKnobs;
|
||||
QList<knobModel*> m_lengthKnobs;
|
||||
QList<boolModel*> m_powerButtons;
|
||||
QList<graphModel*> m_graphs;
|
||||
QList<boolModel*> m_impulses;
|
||||
QList<nineButtonSelectorModel*> m_harmonics;
|
||||
|
||||
static const int m_sampleLength = 128;
|
||||
|
||||
friend class vibedView;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
class vibedView : public instrumentView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
vibedView( instrument * _instrument,
|
||||
QWidget * _parent );
|
||||
virtual ~vibedView() {};
|
||||
|
||||
public slots:
|
||||
void showString( Uint8 _string );
|
||||
void contextMenuEvent( QContextMenuEvent * );
|
||||
void displayHelp( void );
|
||||
|
||||
|
||||
protected slots:
|
||||
void sinWaveClicked( void );
|
||||
void triangleWaveClicked( void );
|
||||
void sawWaveClicked( void );
|
||||
void sqrWaveClicked( void );
|
||||
void noiseWaveClicked( void );
|
||||
void usrWaveClicked( void );
|
||||
void smoothClicked( void );
|
||||
void normalizeClicked( void );
|
||||
|
||||
private:
|
||||
QList<knob*> m_pickKnobs;
|
||||
QList<knob*> m_pickupKnobs;
|
||||
QList<knob*> m_stiffnessKnobs;
|
||||
QList<volumeKnob*> m_volumeKnobs;
|
||||
QList<knob*> m_panKnobs;
|
||||
QList<knob*> m_detuneKnobs;
|
||||
QList<knob*> m_randomKnobs;
|
||||
QList<knob*> m_lengthKnobs;
|
||||
QList<impulseEditor*> m_editors;
|
||||
QList<ledCheckBox*> m_impulses;
|
||||
QList<nineButtonSelector*> m_harmonics;
|
||||
|
||||
virtual void modelChanged( void );
|
||||
|
||||
|
||||
// String-related
|
||||
knob * m_pickKnob;
|
||||
knob * m_pickupKnob;
|
||||
knob * m_stiffnessKnob;
|
||||
@@ -82,15 +117,25 @@ private:
|
||||
knob * m_detuneKnob;
|
||||
knob * m_randomKnob;
|
||||
knob * m_lengthKnob;
|
||||
impulseEditor * m_editor;
|
||||
|
||||
nineButtonSelector * m_stringSelector;
|
||||
graph * m_graph;
|
||||
nineButtonSelector * m_harmonic;
|
||||
|
||||
ledCheckBox * m_impulse;
|
||||
|
||||
int m_sampleLength;
|
||||
} ;
|
||||
ledCheckBox * m_power;
|
||||
|
||||
// Not in model
|
||||
nineButtonSelector * m_stringSelector;
|
||||
pixmapButton * m_smoothBtn;
|
||||
pixmapButton * m_normalizeBtn;
|
||||
|
||||
// From impulse editor
|
||||
pixmapButton * m_sinWaveBtn;
|
||||
pixmapButton * m_triangleWaveBtn;
|
||||
pixmapButton * m_sqrWaveBtn;
|
||||
pixmapButton * m_sawWaveBtn;
|
||||
pixmapButton * m_whiteNoiseWaveBtn;
|
||||
pixmapButton * m_usrWaveBtn;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -871,9 +871,10 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
|
||||
x -= WHITE_KEY_WIDTH;
|
||||
|
||||
// get tact-64th in which the user clicked
|
||||
int pos_tact_64th = x * 64 / m_ppt +
|
||||
int pos_tact_64th = (x-1) * 64 / m_ppt +
|
||||
m_currentPosition;
|
||||
|
||||
|
||||
// get note-vector of current pattern
|
||||
const noteVector & notes = m_pattern->notes();
|
||||
|
||||
@@ -939,7 +940,10 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
|
||||
pattern::MelodyPattern );
|
||||
|
||||
// then set new note
|
||||
midiTime note_pos( pos_tact_64th );
|
||||
// +32 to quanitize the note correctly when placing notes with
|
||||
// the mouse. We do this here instead of in note.quantized
|
||||
// because live notes should still be quantized at the half.
|
||||
midiTime note_pos( pos_tact_64th - (quantization() / 2) );
|
||||
midiTime note_len( newNoteLen() );
|
||||
|
||||
note new_note( note_len, note_pos,
|
||||
|
||||
478
src/widgets/graph.cpp
Normal file
478
src/widgets/graph.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* graph.cpp - a QT widget for displaying and manipulating waveforms
|
||||
*
|
||||
* Copyright (c) 2006-2007 Andreas Brandmaier <andy/at/brandmaier/dot/de>
|
||||
* 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
*
|
||||
* 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/QPaintEvent>
|
||||
#include <QtGui/QFontMetrics>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
#include "graph.h"
|
||||
#include "string_pair_drag.h"
|
||||
#include "sample_buffer.h"
|
||||
#include "oscillator.h"
|
||||
//#include <cstdlib>
|
||||
//#include <math.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
graph::graph( QWidget * _parent ) :
|
||||
QWidget( _parent ),
|
||||
/* TODO: size, background? */
|
||||
modelView( new graphModel( -1.0, 1.0, 128, NULL, NULL, TRUE ) )
|
||||
{
|
||||
m_mouseDown = false;
|
||||
|
||||
resize( 132, 104 );
|
||||
setAcceptDrops( TRUE );
|
||||
|
||||
graphModel * gModel = castModel<graphModel>();
|
||||
|
||||
QObject::connect( gModel, SIGNAL( samplesChanged( int, int ) ),
|
||||
this, SLOT( updateGraph( int, int ) ) );
|
||||
}
|
||||
|
||||
|
||||
graph::~graph()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::setForeground( const QPixmap &_pixmap )
|
||||
{
|
||||
m_foreground = _pixmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void graph::loadSampleFromFile( const QString & _filename )
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
// zero sample_shape
|
||||
for( i = 0; i < sampleLength; i++ )
|
||||
{
|
||||
samplePointer[i] = 0;
|
||||
}
|
||||
|
||||
// load user shape
|
||||
sampleBuffer buffer( _filename );
|
||||
|
||||
// copy buffer data
|
||||
int trimSize = fmin( size(), static_cast<int>(buffer.frames()) );
|
||||
|
||||
|
||||
for( i = 0; i < trimSize; i++ )
|
||||
{
|
||||
samplePointer[i] = (float)*buffer.data()[i];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void graph::mouseMoveEvent ( QMouseEvent * _me )
|
||||
{
|
||||
// get position
|
||||
int x = _me->x();
|
||||
int y = _me->y();
|
||||
|
||||
static bool skip = false;
|
||||
|
||||
if( skip )
|
||||
{
|
||||
skip = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid mouse leaps
|
||||
int diff = x - m_lastCursorX;
|
||||
|
||||
if( diff >= 1 )
|
||||
{
|
||||
x = min( width() - 3, m_lastCursorX + 1);
|
||||
}
|
||||
else if( diff <= 1 )
|
||||
{
|
||||
x = max( 2, m_lastCursorX - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
x = m_lastCursorX;
|
||||
}
|
||||
|
||||
y = max( 2, min( y, height()-3 ) );
|
||||
|
||||
changeSampleAt( x, y );
|
||||
|
||||
// update mouse
|
||||
m_lastCursorX = x;
|
||||
|
||||
QPoint pt = mapToGlobal( QPoint( x, y ) );
|
||||
|
||||
QCursor::setPos( pt.x(), pt.y() );
|
||||
|
||||
skip = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::mousePressEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() == Qt::LeftButton )
|
||||
{
|
||||
// toggle mouse state
|
||||
m_mouseDown = true;
|
||||
|
||||
// get position
|
||||
int x = _me->x();
|
||||
int y = _me->y();
|
||||
|
||||
changeSampleAt( x, y );
|
||||
|
||||
// toggle mouse state
|
||||
m_mouseDown = true;
|
||||
setCursor( Qt::BlankCursor );
|
||||
m_lastCursorX = x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::changeSampleAt(int _x, int _y)
|
||||
{
|
||||
float minVal = model()->minValue();
|
||||
float maxVal = model()->maxValue();
|
||||
|
||||
if ( width() <= 4 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float xscale = static_cast<float>( model()->length() ) /
|
||||
( width()-4 );
|
||||
|
||||
// consider border of background image
|
||||
_x -= 2;
|
||||
_y -= 2;
|
||||
|
||||
// subtract max from min because Qt's Y-axis is backwards
|
||||
float range = minVal - maxVal;
|
||||
float val = ( _y*range/( height()-4 ) ) + maxVal;
|
||||
|
||||
model()->setSampleAt( _x*xscale, val );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::mouseReleaseEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() == Qt::LeftButton )
|
||||
{
|
||||
// toggle mouse state
|
||||
m_mouseDown = false;
|
||||
setCursor( Qt::ArrowCursor );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter p( this );
|
||||
|
||||
p.setPen( QPen(QColor( 0xFF, 0xAA, 0x00 ), 1) );
|
||||
|
||||
QVector<float> * samps = &(model()->m_samples);
|
||||
int length = model()->length();
|
||||
int maxVal = model()->maxValue();
|
||||
|
||||
float xscale = ( width()-4 ) / length;
|
||||
float yscale = (float)( height()-4 ) / ( model()->minValue() - maxVal );
|
||||
|
||||
// Max index, more useful below
|
||||
length--;
|
||||
|
||||
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 )
|
||||
);
|
||||
}
|
||||
|
||||
// Draw last segment flat
|
||||
p.drawLine(2+static_cast<int>(length*xscale),
|
||||
2+static_cast<int>( ( (*samps)[length] - maxVal ) * yscale ),
|
||||
width()-2,
|
||||
2+static_cast<int>( ( (*samps)[length] - maxVal ) * yscale ) );
|
||||
|
||||
p.setRenderHints( QPainter::Antialiasing, FALSE );
|
||||
|
||||
// draw Pointer
|
||||
if( m_mouseDown )
|
||||
{
|
||||
QPoint cursor = mapFromGlobal( QCursor::pos() );
|
||||
p.setPen( QColor( 0xAA, 0xFF, 0x00 ) );
|
||||
p.drawLine( 2, cursor.y(), width()-2, cursor.y() );
|
||||
p.drawLine( cursor.x(), 2, cursor.x(), height()-2 );
|
||||
}
|
||||
p.drawPixmap( 0, 0, m_foreground );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
QString type = stringPairDrag::decodeKey( _de );
|
||||
QString value = stringPairDrag::decodeValue( _de );
|
||||
|
||||
if( type == "samplefile" )
|
||||
{
|
||||
// TODO: call setWaveToUser
|
||||
// loadSampleFromFile( value );
|
||||
_de->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void graph::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
if( stringPairDrag::processDragEnterEvent( _dee,
|
||||
QString( "samplefile" ) ) == FALSE )
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::modelChanged( void )
|
||||
{
|
||||
graphModel * gModel = castModel<graphModel>();
|
||||
|
||||
QObject::connect( gModel, SIGNAL( samplesChanged( Uint32, Uint32 ) ),
|
||||
this, SLOT( updateGraph( Uint32, Uint32 ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graph::updateGraph( Uint32 _startPos, Uint32 _endPos )
|
||||
{
|
||||
// Can optimize by only drawing changed position
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
graphModel::graphModel( float _min, float _max, Uint32 _length,
|
||||
::model * _parent, track * _track,
|
||||
bool _default_constructed ) :
|
||||
model( _parent, _default_constructed ),
|
||||
m_minValue( _min ),
|
||||
m_maxValue( _max ),
|
||||
m_samples( _length )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
graphModel::~graphModel()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::setRange( float _min, float _max )
|
||||
{
|
||||
if( _min != m_minValue || _max != m_maxValue )
|
||||
{
|
||||
m_minValue = _min;
|
||||
m_maxValue = _max;
|
||||
|
||||
if( !m_samples.isEmpty() )
|
||||
{
|
||||
// Trim existing values
|
||||
for( int i=0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = fmaxf( _min, fminf( m_samples[i], _max ) );
|
||||
}
|
||||
}
|
||||
|
||||
emit rangeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::setLength( Uint32 _length )
|
||||
{
|
||||
if( _length != length() )
|
||||
{
|
||||
m_samples.resize( _length );
|
||||
emit lengthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::setSampleAt( Uint32 _x, float _val )
|
||||
{
|
||||
// boundary check
|
||||
if ( _x >= 0 && _x < length() &&
|
||||
_val >= minValue() && _val < maxValue() )
|
||||
{
|
||||
|
||||
// change sample shape
|
||||
m_samples[_x] = _val;
|
||||
emit samplesChanged( _x, _x );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::setSamples( const float * _samples )
|
||||
{
|
||||
qCopy( _samples, _samples + length(), m_samples.begin());
|
||||
|
||||
emit samplesChanged( 0, length()-1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::setWaveToSine( void )
|
||||
{
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = oscillator::sinSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
|
||||
emit samplesChanged( 0, length() - 1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
void graphModel::setWaveToTriangle( void )
|
||||
{
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = oscillator::triangleSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
|
||||
emit samplesChanged( 0, length() - 1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
void graphModel::setWaveToSaw( void )
|
||||
{
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = oscillator::sawSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
|
||||
emit samplesChanged( 0, length() - 1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
void graphModel::setWaveToSquare( void )
|
||||
{
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = oscillator::squareSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
|
||||
emit samplesChanged( 0, length() - 1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
void graphModel::setWaveToNoise( void )
|
||||
{
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = oscillator::noiseSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
|
||||
emit samplesChanged( 0, length() - 1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
void graphModel::smooth( void )
|
||||
{
|
||||
// store values in temporary array
|
||||
QVector<float> temp = m_samples;
|
||||
|
||||
// Smoothing
|
||||
m_samples[0] = ( temp[0] + temp[length()-1] ) * 0.5f;
|
||||
for ( Uint32 i=1; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = ( temp[i-1] + temp[i] ) * 0.5f;
|
||||
}
|
||||
|
||||
emit samplesChanged(0, length()-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void graphModel::normalize( void )
|
||||
{
|
||||
float max = 0.0001f;
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
if( fabsf(m_samples[i]) > max && m_samples[i] != 0.0f )
|
||||
{
|
||||
max = fabs( m_samples[i] );
|
||||
}
|
||||
}
|
||||
|
||||
for( Uint32 i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] /= max;
|
||||
}
|
||||
|
||||
if( max != 1.0f ) {
|
||||
emit samplesChanged( 0, length()-1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "graph.moc"
|
||||
Reference in New Issue
Block a user