diff --git a/ChangeLog b/ChangeLog index a382e81ef..fe2c9e3ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +2008-02-22 Paul Giblock + + * 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 * plugins/ladspa_effect/ladspa_subplugin_features.h: diff --git a/Makefile.am b/Makefile.am index 772d18160..ff26fdef2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/plugins/vibed/graph.h b/include/graph.h similarity index 50% rename from plugins/vibed/graph.h rename to include/graph.h index 9e8147542..095f9b73b 100644 --- a/plugins/vibed/graph.h +++ b/include/graph.h @@ -2,6 +2,7 @@ * graph.h - a QT widget for displaying and manipulating waveforms * * Copyright (c) 2006-2007 Andreas Brandmaier + * 2008 Paul Giblock * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -30,21 +31,26 @@ #include #include +#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(); + } -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 m_samples; + float m_maxValue; + float m_minValue; + + friend class graph; + +}; + #endif diff --git a/plugins/stereo_enhancer/Makefile.am b/plugins/stereo_enhancer/Makefile.am index 7789ccb55..e64807721 100644 --- a/plugins/stereo_enhancer/Makefile.am +++ b/plugins/stereo_enhancer/Makefile.am @@ -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 diff --git a/plugins/stereo_enhancer/stereo_enhancer.cpp b/plugins/stereo_enhancer/stereo_enhancer.cpp index 43ac9b588..d684e87fa 100644 --- a/plugins/stereo_enhancer/stereo_enhancer.cpp +++ b/plugins/stereo_enhancer/stereo_enhancer.cpp @@ -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( _data ) ) ); } diff --git a/plugins/stereo_enhancer/stereo_enhancer.h b/plugins/stereo_enhancer/stereo_enhancer.h index bc937588d..7796f084a 100644 --- a/plugins/stereo_enhancer/stereo_enhancer.h +++ b/plugins/stereo_enhancer/stereo_enhancer.h @@ -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 > m_seFX; effectLib::stereoEnhancer<> m_seFX; surroundSampleFrame * m_delayBuffer; int m_currFrame; + stereoEnhancerControls m_bbControls; - friend class stereoEnhancerControlDialog; + friend class stereoEnhancerControls; } ; - - #endif diff --git a/plugins/stereo_enhancer/stereoenhancer_control_dialog.cpp b/plugins/stereo_enhancer/stereoenhancer_control_dialog.cpp index bb1b3d006..8b4da06f2 100644 --- a/plugins/stereo_enhancer/stereoenhancer_control_dialog.cpp +++ b/plugins/stereo_enhancer/stereoenhancer_control_dialog.cpp @@ -23,68 +23,27 @@ */ -#ifndef QT3 #include -#include -#else - -#include - -#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" - diff --git a/plugins/stereo_enhancer/stereoenhancer_control_dialog.h b/plugins/stereo_enhancer/stereoenhancer_control_dialog.h index c3b7eed5e..5ba9de711 100644 --- a/plugins/stereo_enhancer/stereoenhancer_control_dialog.h +++ b/plugins/stereo_enhancer/stereoenhancer_control_dialog.h @@ -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 diff --git a/plugins/stereo_enhancer/stereoenhancer_controls.cpp b/plugins/stereo_enhancer/stereoenhancer_controls.cpp new file mode 100644 index 000000000..452c33000 --- /dev/null +++ b/plugins/stereo_enhancer/stereoenhancer_controls.cpp @@ -0,0 +1,68 @@ +/* + * stereoenhancer_controls.cpp - control-dialog for stereoenhancer-effect + * + * Copyright (c) 2006-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "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" + diff --git a/plugins/stereo_enhancer/stereoenhancer_controls.h b/plugins/stereo_enhancer/stereoenhancer_controls.h new file mode 100644 index 000000000..df51a8750 --- /dev/null +++ b/plugins/stereo_enhancer/stereoenhancer_controls.h @@ -0,0 +1,74 @@ +/* + * stereoenhancer_controls.h - controls for stereoEnhancer-effect + * + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef _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*/ diff --git a/plugins/vibed/Makefile.am b/plugins/vibed/Makefile.am index 81f20ac8e..5f1258c0b 100644 --- a/plugins/vibed/Makefile.am +++ b/plugins/vibed/Makefile.am @@ -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 diff --git a/plugins/vibed/graph.cpp b/plugins/vibed/graph.cpp deleted file mode 100644 index c66726dc4..000000000 --- a/plugins/vibed/graph.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * graph.cpp - a QT widget for displaying and manipulating waveforms - * - * Copyright (c) 2006-2007 Andreas Brandmaier - * - * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - */ - - -#include -#include -#include - -#include "graph.h" -#include "string_pair_drag.h" -#include "sample_buffer.h" -#include -#include - -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(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(i*xscale), - 2+static_cast(-samplePointer[i]*50) + 50, - 2+static_cast((i+1)*xscale), - 2+static_cast(-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" diff --git a/plugins/vibed/impulse_editor.cpp b/plugins/vibed/impulse_editor.cpp deleted file mode 100644 index 1d0b7c989..000000000 --- a/plugins/vibed/impulse_editor.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/* - * impulse_editor.cpp - graphic waveform editor - * - * Copyright (c) 2006-2007 Danny McRae - * - * 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 -#include -#include -#include - -#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( 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( 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( 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( 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( 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( buffer.frames() ) ) - { - m_sampleLength = m_sampleLength; - } - else - { - m_sampleLength = static_cast( buffer.frames() ); - } - for( Uint32 i = 0; i < m_sampleLength; i++ ) - { - m_sampleShape[i] = static_cast( - 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" - diff --git a/plugins/vibed/impulse_editor.h b/plugins/vibed/impulse_editor.h deleted file mode 100644 index 28751ef7f..000000000 --- a/plugins/vibed/impulse_editor.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * impulse_editor.cpp - graphic waveform editor - * - * Copyright (c) 2006-2007 Danny McRae - * - * 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 -#include -#include - -#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 diff --git a/plugins/vibed/nine_button_selector.cpp b/plugins/vibed/nine_button_selector.cpp index b7c5f9a52..55b5dcb82 100644 --- a/plugins/vibed/nine_button_selector.cpp +++ b/plugins/vibed/nine_button_selector.cpp @@ -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 * ) { diff --git a/plugins/vibed/nine_button_selector.h b/plugins/vibed/nine_button_selector.h index 3dc21a2f4..8db59273e 100644 --- a/plugins/vibed/nine_button_selector.h +++ b/plugins/vibed/nine_button_selector.h @@ -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()->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 m_buttons; pixmapButton * m_button; pixmapButton * m_lastBtn; QPixmap m_base; - + Uint8 m_selected; + }; + +typedef nineButtonSelector::autoModel nineButtonSelectorModel; + #endif diff --git a/plugins/vibed/string_container.cpp b/plugins/vibed/string_container.cpp index 67ab176d1..ca57af6d9 100644 --- a/plugins/vibed/string_container.cpp +++ b/plugins/vibed/string_container.cpp @@ -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(_impulse), m_bufferLength, m_sampleRate, _oversample, diff --git a/plugins/vibed/string_container.h b/plugins/vibed/string_container.h index bc35f28ca..c1daf0df8 100644 --- a/plugins/vibed/string_container.h +++ b/plugins/vibed/string_container.h @@ -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, diff --git a/plugins/vibed/vibed.cpp b/plugins/vibed/vibed.cpp index 6ff6e204a..8d2667ab3 100644 --- a/plugins/vibed/vibed.cpp +++ b/plugins/vibed/vibed.cpp @@ -23,22 +23,22 @@ */ -#include "vibed.h" - #include #include #include -#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 ", 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( _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( 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( - _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(); + + 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" { diff --git a/plugins/vibed/vibed.h b/plugins/vibed/vibed.h index 4a14c819f..6423384be 100644 --- a/plugins/vibed/vibed.h +++ b/plugins/vibed/vibed.h @@ -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 m_pickKnobs; + QList m_pickupKnobs; + QList m_stiffnessKnobs; + QList m_volumeKnobs; + QList m_panKnobs; + QList m_detuneKnobs; + QList m_randomKnobs; + QList m_lengthKnobs; + QList m_powerButtons; + QList m_graphs; + QList m_impulses; + QList 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 m_pickKnobs; - QList m_pickupKnobs; - QList m_stiffnessKnobs; - QList m_volumeKnobs; - QList m_panKnobs; - QList m_detuneKnobs; - QList m_randomKnobs; - QList m_lengthKnobs; - QList m_editors; - QList m_impulses; - QList 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 diff --git a/src/core/piano_roll.cpp b/src/core/piano_roll.cpp index 727fffee0..6aadf3eda 100644 --- a/src/core/piano_roll.cpp +++ b/src/core/piano_roll.cpp @@ -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, diff --git a/src/widgets/graph.cpp b/src/widgets/graph.cpp new file mode 100644 index 000000000..eb44ad10c --- /dev/null +++ b/src/widgets/graph.cpp @@ -0,0 +1,478 @@ +/* + * graph.cpp - a QT widget for displaying and manipulating waveforms + * + * Copyright (c) 2006-2007 Andreas Brandmaier + * 2008 Paul Giblock + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include +#include +#include + +#include "graph.h" +#include "string_pair_drag.h" +#include "sample_buffer.h" +#include "oscillator.h" +//#include +//#include + +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(); + + 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(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( 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 * 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(i*xscale), + 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ), + 2+static_cast((i+1)*xscale), + 2+static_cast( ( (*samps)[i+1] - maxVal ) * yscale ) + ); + } + + // Draw last segment flat + p.drawLine(2+static_cast(length*xscale), + 2+static_cast( ( (*samps)[length] - maxVal ) * yscale ), + width()-2, + 2+static_cast( ( (*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(); + + 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( 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( 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( 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( 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( length() ) ); + } + + emit samplesChanged( 0, length() - 1 ); +}; + + + +void graphModel::smooth( void ) +{ + // store values in temporary array + QVector 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"