diff --git a/ChangeLog b/ChangeLog index dad6c29e62..2f7c0fd0a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,93 @@ +2008-02-16 Tobias Doerffel + + * plugins/ladspa_effect/ladspa_controls.cpp: + * plugins/audio_file_processor/audio_file_processor.cpp: + * plugins/stk/Makefile.am: + * include/mmp.h: + * include/instrument_midi_io_view.h: + * include/track.h: + * include/engine.h: + * include/name_label.h: + * include/instrument_track.h: + * include/instrument_functions.h: + * include/piano_widget.h: + * include/song.h: + * include/pattern.h: + * include/file_browser.h: + * include/envelope_and_lfo_parameters.h: + * include/envelope_and_lfo_view.h: + * include/instrument_sound_shaping.h: + * include/instrument_function_views.h: + * include/instrument_midi_io.h: + * include/bb_track.h: + * include/song_editor.h: + * include/dummy_instrument.h: + * include/journalling_object.h: + * include/sample_track.h: + * include/timeline.h: + * include/main_window.h: + * include/mv_base.h: + * include/bb_editor.h: + * include/arp_and_chords_tab_widget.h: + * include/automation_track.h: + * include/track_container.h: + * include/instrument_sound_shaping_view.h: + * configure.in: + * src/midi/midi_alsa_seq.cpp: + * src/lib/project_journal.cpp: + * src/lib/mmp.cpp: + * src/lib/journalling_object.cpp: + * src/widgets/instrument_sound_shaping_view.cpp: + * src/widgets/envelope_and_lfo_view.cpp: + * src/widgets/instrument_function_views.cpp: + * src/widgets/instrument_midi_io_view.cpp: + * src/widgets/project_notes.cpp: + * src/widgets/effect_rack_view.cpp: + * src/widgets/automatable_button.cpp: + * src/widgets/tempo_sync_knob.cpp: + * src/tracks/automation_track.cpp: + * src/tracks/sample_track.cpp: + * src/tracks/bb_track.cpp: + * src/tracks/instrument_track.cpp: + * src/tracks/pattern.cpp: + * src/core/arp_and_chords_tab_widget.cpp: + * src/core/preset_preview_play_handle.cpp: + * src/core/note_play_handle.cpp: + * src/core/track_container.cpp: + * src/core/song.cpp: + * src/core/import_filter.cpp: + * src/core/file_browser.cpp: + * src/core/envelope_and_lfo_parameters.cpp: + * src/core/mixer.cpp: + * src/core/main.cpp: + * src/core/export_project_dialog.cpp: + * src/core/instrument_sound_shaping.cpp: + * src/core/piano_roll.cpp: + * src/core/instrument_functions.cpp: + * src/core/instrument_midi_io.cpp: + * src/core/track.cpp: + * src/core/engine.cpp: + * src/core/timeline.cpp: + * src/core/instrument.cpp: + * src/core/piano_widget.cpp: + * src/core/main_window.cpp: + * src/core/song_editor.cpp: + * src/core/mv_base.cpp: + * src/core/automation_pattern.cpp: + * src/core/name_label.cpp: + * src/core/automation_editor.cpp: + * src/core/bb_editor.cpp: + * Makefile.am: + finally splitted rest of LMMS, i.e. tracks, track-containers, + track-content-objects, whole instrument-track/instrument-track-window + and so on - still a bit unstable but I'm sure we'll manage to get this + one very stable! + + diffstat says: + 79 files changed, 8019 insertions(+), 6226 deletions(-) + 2008-02-01 Danny McRae + * Makefile.am: * src/tracks/instrument_track.cpp: * src/core/note_play_handle.cpp: @@ -209,6 +298,7 @@ Makefile.am in plugins/stk to get them to build. 2007-01-30 Paul Giblock + * plugins/organic/organic.cpp: * plugins/organic/organic.h: Began split on Organic. But doesn't show in instrument list @@ -217,6 +307,7 @@ Fixed comments 2008-01-28 Paul Giblock + * plugins/lb302/lb302.cpp: * plugins/lb302/lb302.h: finished LB302 M/V-split. however, more changes can be made to meet diff --git a/Makefile.am b/Makefile.am index b941476355..772d18160b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,6 @@ man1_MANS = lmms.1 lmms_MOC = \ ./about_dialog.moc \ - ./arp_and_chords_tab_widget.moc \ ./automatable_button.moc \ ./automatable_slider.moc \ ./automation_editor.moc \ @@ -64,11 +63,13 @@ lmms_MOC = \ ./effect_label.moc \ ./effect_select_dialog.moc \ ./envelope_and_lfo_parameters.moc \ - ./instrument_sound_shaping.moc \ + ./envelope_and_lfo_view.moc \ ./export_project_dialog.moc \ ./fade_button.moc \ ./file_browser.moc \ ./group_box.moc \ + ./instrument_midi_io.moc \ + ./instrument_midi_io_view.moc \ ./kmultitabbar.moc \ ./knob.moc \ ./ladspa_control.moc \ @@ -97,6 +98,7 @@ lmms_MOC = \ ./setup_dialog.moc \ ./side_bar.moc \ ./side_bar_widget.moc \ + ./song.moc \ ./song_editor.moc \ ./surround_area.moc \ ./tab_bar.moc \ @@ -150,7 +152,6 @@ lmms_SOURCES = \ $(srcdir)/src/audio/audio_sample_recorder.cpp \ $(srcdir)/src/audio/audio_sdl.cpp \ $(srcdir)/src/core/about_dialog.cpp \ - $(srcdir)/src/core/arp_and_chords_tab_widget.cpp \ $(srcdir)/src/core/automation_editor.cpp \ $(srcdir)/src/core/automation_pattern.cpp \ $(srcdir)/src/core/bb_editor.cpp \ @@ -166,6 +167,7 @@ lmms_SOURCES = \ $(srcdir)/src/core/file_browser.cpp \ $(srcdir)/src/core/import_filter.cpp \ $(srcdir)/src/core/instrument.cpp \ + $(srcdir)/src/core/instrument_functions.cpp \ $(srcdir)/src/core/ladspa_2_lmms.cpp \ $(srcdir)/src/core/ladspa_manager.cpp \ $(srcdir)/src/core/ladspa_control.cpp \ @@ -185,7 +187,7 @@ lmms_SOURCES = \ $(srcdir)/src/core/preset_preview_play_handle.cpp \ $(srcdir)/src/core/sample_play_handle.cpp \ $(srcdir)/src/core/setup_dialog.cpp \ - $(srcdir)/src/core/song_editor.cpp \ + $(srcdir)/src/core/song.cpp \ $(srcdir)/src/core/tool.cpp \ $(srcdir)/src/core/track.cpp \ $(srcdir)/src/core/track_container.cpp \ @@ -212,7 +214,6 @@ lmms_SOURCES = \ $(srcdir)/src/tracks/bb_track.cpp \ $(srcdir)/src/tracks/instrument_track.cpp \ $(srcdir)/src/tracks/pattern.cpp \ - $(srcdir)/src/tracks/sample_track.cpp \ $(srcdir)/src/widgets/automatable_button.cpp \ $(srcdir)/src/widgets/automatable_slider.cpp \ $(srcdir)/src/widgets/caption_menu.cpp \ @@ -223,6 +224,10 @@ lmms_SOURCES = \ $(srcdir)/src/widgets/effect_view.cpp \ $(srcdir)/src/widgets/fade_button.cpp \ $(srcdir)/src/widgets/group_box.cpp \ + $(srcdir)/src/widgets/envelope_and_lfo_view.cpp \ + $(srcdir)/src/widgets/instrument_function_views.cpp \ + $(srcdir)/src/widgets/instrument_midi_io_view.cpp \ + $(srcdir)/src/widgets/instrument_sound_shaping_view.cpp \ $(srcdir)/src/widgets/kmultitabbar.cpp \ $(srcdir)/src/widgets/knob.cpp \ $(srcdir)/src/widgets/ladspa_control_view.cpp \ @@ -234,6 +239,7 @@ lmms_SOURCES = \ $(srcdir)/src/widgets/rubberband.cpp \ $(srcdir)/src/widgets/rename_dialog.cpp \ $(srcdir)/src/widgets/side_bar_widget.cpp \ + $(srcdir)/src/core/song_editor.cpp \ $(srcdir)/src/widgets/tab_bar.cpp \ $(srcdir)/src/widgets/tab_widget.cpp \ $(srcdir)/src/widgets/text_float.cpp \ @@ -270,6 +276,7 @@ lmms_SOURCES = \ $(srcdir)/include/note.h \ $(srcdir)/include/volume.h \ $(srcdir)/include/panning.h \ + $(srcdir)/include/song.h \ $(srcdir)/include/song_editor.h \ $(srcdir)/include/plugin.h \ $(srcdir)/include/plugin_view.h \ @@ -284,11 +291,14 @@ lmms_SOURCES = \ $(srcdir)/include/note_play_handle.h \ $(srcdir)/include/piano_roll.h \ $(srcdir)/include/basic_filters.h \ + $(srcdir)/include/envelope_and_lfo_parameters.h \ $(srcdir)/include/instrument_sound_shaping.h \ $(srcdir)/include/envelope_and_lfo_parameters.h \ $(srcdir)/include/about_dialog.h \ $(srcdir)/include/oscillator.h \ - $(srcdir)/include/arp_and_chords_tab_widget.h \ + $(srcdir)/include/instrument_functions.h \ + $(srcdir)/include/instrument_function_views.h \ + $(srcdir)/include/instrument_sound_shaping_view.h \ $(srcdir)/include/export.h \ $(srcdir)/include/mv_base.h \ $(srcdir)/include/automatable_model.h \ @@ -351,6 +361,7 @@ lmms_SOURCES = \ $(srcdir)/include/instrument_play_handle.h \ $(srcdir)/include/string_pair_drag.h \ $(srcdir)/include/instrument_midi_io.h \ + $(srcdir)/include/instrument_midi_io_view.h \ $(srcdir)/include/audio_port.h \ $(srcdir)/include/tool.h \ $(srcdir)/include/tool_button.h \ @@ -390,6 +401,7 @@ lmms_SOURCES = \ $(THIRD_PARTY_CODE) +# $(srcdir)/src/tracks/sample_track.cpp EXTRA_DIST = $(lmms_EMBEDDED_RESOURCES) lmms.1 diff --git a/configure.in b/configure.in index 0c8b1edc74..3ad0b608eb 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.4.0-svn20080114-mv, lmms-devel/at/lists/dot/sf/dot/net) -AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080114-mv) +AC_INIT(lmms, 0.4.0-svn20080215-mv, lmms-devel/at/lists/dot/sf/dot/net) +AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080215-mv) AM_CONFIG_HEADER(config.h) @@ -574,7 +574,7 @@ lmmsdatadir="$datadir/$PACKAGE" AC_SUBST(lmmsdatadir) -EXTRA_WARNINGS="-Wextra -Wno-unused-parameter -Wunsafe-loop-optimizations -Wdisabled-optimization" +EXTRA_WARNINGS="-Wno-unused-parameter -Wunsafe-loop-optimizations -Wdisabled-optimization" if test "x$CXX" == "xg++" ; then CXXFLAGS="-ansi -Wall $EXTRA_WARNINGS $CXXFLAGS -fno-exceptions" fi diff --git a/include/arp_and_chords_tab_widget.h b/include/arp_and_chords_tab_widget.h deleted file mode 100644 index 21797cedb8..0000000000 --- a/include/arp_and_chords_tab_widget.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * arp_and_chords_tab_widget.h - declaration of class arpAndChordWidget which - * provides code for using arpeggio and chords - * - * Copyright (c) 2004-2007 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 _ARP_AND_CHORDS_TAB_WIDGET_H -#define _ARP_AND_CHORDS_TAB_WIDGET_H - -#include - -#include "journalling_object.h" -#include "types.h" -#include "automatable_model.h" - - -class QLabel; -class QPixmap; - -class automatableButtonGroup; -class flpImport; -class instrumentTrack; -class comboBox; -class groupBox; -class knob; -class notePlayHandle; -class tempoSyncKnob; -class comboBoxModel; - - -const int MAX_CHORD_POLYPHONY = 10; - - -class arpAndChordsTabWidget : public QWidget, public journallingObject -{ - Q_OBJECT -public: - enum arpDirections - { - UP, - DOWN, - UP_AND_DOWN, - RANDOM - } ; - - arpAndChordsTabWidget( instrumentTrack * _channel_track ); - virtual ~arpAndChordsTabWidget(); - - static struct chord - { - const QString name; - Sint8 interval[MAX_CHORD_POLYPHONY]; - } s_chords[]; - - void FASTCALL processNote( notePlayHandle * _n ); - static inline int getChordSize( chord & _c ) - { - int idx = 0; - while( _c.interval[idx] != -1 ) - { - ++idx; - } - return( idx ); - } - - - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); - inline virtual QString nodeName( void ) const - { - return( "arpandchords" ); - } - - -private: - enum arpModes - { - FREE, - SORT, - SYNC - } ; - - // chord-stuff - groupBox * m_chordsGroupBox; - boolModel * m_chordsEnabledModel; - comboBox * m_chordsComboBox; - comboBoxModel * m_chordsModel; - knob * m_chordRangeKnob; - floatModel * m_chordRangeModel; - - // arpeggio-stuff - groupBox * m_arpGroupBox; - boolModel * m_arpEnabledModel; - comboBox * m_arpComboBox; - comboBoxModel * m_arpModel; - knob * m_arpRangeKnob; - floatModel * m_arpRangeModel; - tempoSyncKnob * m_arpTimeKnob; - floatModel * m_arpTimeModel; - knob * m_arpGateKnob; - floatModel * m_arpGateModel; - - QLabel * m_arpDirectionLbl; - - automatableButtonGroup * m_arpDirectionBtnGrp; - intModel * m_arpDirectionModel; - - comboBox * m_arpModeComboBox; - comboBoxModel * m_arpModeModel; - - - friend class flpImport; - -} ; - - -#endif diff --git a/include/automation_track.h b/include/automation_track.h index d5c421da72..2f97a23915 100644 --- a/include/automation_track.h +++ b/include/automation_track.h @@ -2,7 +2,7 @@ * automation_track.h - declaration of class automationTrack, which handles * automation of objects without a track * - * Copyright (c) 2006 Javier Serrano Polo + * Copyright (c) 2006-2008 Javier Serrano Polo * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -30,34 +30,30 @@ #include "track.h" -class automationTrack : public QWidget, public track +class automationTrack : public track { - Q_OBJECT public: automationTrack( trackContainer * _tc ); virtual ~automationTrack(); - -private: - inline QString nodeName( void ) const - { - return( "automation-track" ); - } - - virtual trackTypes type( void ) const; - - virtual bool FASTCALL play( const midiTime & _start, - const fpp_t _frames, + virtual bool play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _frame_base, Sint16 _tco_num = -1 ); - virtual trackContentObject * FASTCALL createTCO( const midiTime & - _pos ); + virtual QString nodeName( void ) const + { + return( "automationtrack" ); + } - virtual void FASTCALL saveTrackSpecificSettings( QDomDocument & _doc, + virtual trackView * createView( trackContainerView * ) + { + return( NULL ); + } + virtual trackContentObject * createTCO( const midiTime & _pos ); + + virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL loadTrackSpecificSettings( const QDomElement & - _this ); + virtual void loadTrackSpecificSettings( const QDomElement & _this ); } ; diff --git a/include/bb_editor.h b/include/bb_editor.h index e9df4580f9..340d05a482 100644 --- a/include/bb_editor.h +++ b/include/bb_editor.h @@ -1,7 +1,7 @@ /* * bb_editor.h - declaration of class bbEditor, a basic-component of LMMS * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -35,39 +35,36 @@ class QPixmap; class toolButton; -class bbEditor : public trackContainer +class bbTrackContainer : public trackContainer { Q_OBJECT - mapPropertyFromModelPtr(int,currentBB,setCurrentBB,m_bbComboBoxModel); + mapPropertyFromModel(int,currentBB,setCurrentBB,m_bbComboBoxModel); public: - virtual bool FASTCALL play( midiTime _start, const fpp_t _frames, + bbTrackContainer( void ); + virtual ~bbTrackContainer(); + + virtual bool play( midiTime _start, const fpp_t _frames, const f_cnt_t _frame_base, Sint16 _tco_num = -1 ); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); +// virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); +// virtual void loadSettings( const QDomElement & _this ); virtual void updateAfterTrackAdd( void ); inline virtual QString nodeName( void ) const { - return( "bbeditor" ); + return( "bbtrackcontainer" ); } - virtual inline bool fixedTCOs( void ) const - { - return( TRUE ); - } - - tact FASTCALL lengthOfBB( const int _bb ); + tact lengthOfBB( int _bb ); inline tact lengthOfCurrentBB( void ) { return( lengthOfBB( currentBB() ) ); } - void FASTCALL removeBB( const int _bb ); int numOfBBs( void ) const; + void removeBB( int _bb ); - void FASTCALL swapBB( const int _bb1, const int _bb2 ); + void swapBB( int _bb1, int _bb2 ); void updateBBTrack( trackContentObject * _tco ); @@ -79,27 +76,49 @@ public slots: void currentBBChanged( void ); -protected: - virtual void keyPressEvent( QKeyEvent * _ke ); +private: + void createTCOsForBB( int _bb ); + + comboBoxModel m_bbComboBoxModel; + + + friend class bbEditor; + +} ; + + + +class bbEditor : public trackContainerView +{ + Q_OBJECT +public: + bbEditor( bbTrackContainer * _tc ); + virtual ~bbEditor(); + + virtual inline bool fixedTCOs( void ) const + { + return( TRUE ); + } + + void removeBBView( int _bb ); + + +public slots: + void play( void ); + void stop( void ); + void updatePosition( void ); private: - bbEditor( void ); - //bbEditor( const bbEditor & ); - virtual ~bbEditor(); - - void FASTCALL createTCOsForBB( const int _bb ); - + virtual void keyPressEvent( QKeyEvent * _ke ); + bbTrackContainer * m_bbtc; QWidget * m_toolBar; toolButton * m_playButton; toolButton * m_stopButton; comboBox * m_bbComboBox; - comboBoxModel * m_bbComboBoxModel; - - friend class engine; } ; diff --git a/include/bb_track.h b/include/bb_track.h index cc65cd96d1..0286046720 100644 --- a/include/bb_track.h +++ b/include/bb_track.h @@ -2,7 +2,7 @@ * bb_track.h - class bbTrack, a wrapper for using bbEditor * (which is a singleton-class) as track * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -38,27 +38,51 @@ class trackContainer; class bbTCO : public trackContentObject { - Q_OBJECT public: - bbTCO( track * _track, const QColor & _c = QColor() ); + bbTCO( track * _track, unsigned int _color = 0 ); virtual ~bbTCO(); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { return( "bbtco" ); } - const QColor & color( void ) const + inline unsigned int color( void ) const { return( m_color ); } + virtual trackContentObjectView * createView( trackView * _tv ); + + +private: + QString m_name; + unsigned int m_color; + + + friend class bbTCOView; + +} ; + + + +class bbTCOView : public trackContentObjectView +{ + Q_OBJECT +public: + bbTCOView( trackContentObject * _tco, trackView * _tv ); + virtual ~bbTCOView(); + + QColor color( void ) const + { + return( m_bbTCO->m_color ); + } + void setColor( QColor _new_color ); + protected slots: - void openInBBEditor( bool _c ); void openInBBEditor( void ); void resetName( void ); void changeName( void ); @@ -72,62 +96,48 @@ protected: private: - QString m_name; - QColor m_color; - - void setColor( QColor _new_color ); + bbTCO * m_bbTCO; } ; -class bbTrack : public QObject, public track + +class bbTrack : public track { - Q_OBJECT public: bbTrack( trackContainer * _tc ); virtual ~bbTrack(); - virtual trackTypes type( void ) const; - virtual bool FASTCALL play( const midiTime & _start, + virtual bool play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _frame_base, Sint16 _tco_num = -1 ); - virtual trackContentObject * FASTCALL createTCO( const midiTime & - _pos ); + virtual trackView * createView( trackContainerView * _tcv ); + virtual trackContentObject * createTCO( const midiTime & _pos ); - virtual void FASTCALL saveTrackSpecificSettings( QDomDocument & _doc, + virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL loadTrackSpecificSettings( const QDomElement & - _this ); + virtual void loadTrackSpecificSettings( const QDomElement & _this ); - static bbTrack * FASTCALL findBBTrack( int _bb_num ); - static int FASTCALL numOfBBTrack( track * _track ); - static void FASTCALL swapBBTracks( track * _track1, track * _track2 ); - - inline nameLabel * trackLabel( void ) - { - return( m_trackLabel ); - } + static bbTrack * findBBTrack( int _bb_num ); + static int numOfBBTrack( track * _track ); + static void swapBBTracks( track * _track1, track * _track2 ); bool automationDisabled( track * _track ) { - return( m_disabled_tracks.contains( _track ) ); + return( m_disabledTracks.contains( _track ) ); } void disableAutomation( track * _track ) { - m_disabled_tracks.append( _track ); + m_disabledTracks.append( _track ); } void enableAutomation( track * _track ) { - m_disabled_tracks.removeAll( _track ); + m_disabledTracks.removeAll( _track ); } -public slots: - void clickedTrackLabel( void ); - - protected: inline virtual QString nodeName( void ) const { @@ -136,13 +146,43 @@ protected: private: - nameLabel * m_trackLabel; - QList m_disabled_tracks; + QList m_disabledTracks; typedef QMap infoMap; static infoMap s_infoMap; + + friend class bbTrackView; + } ; + +class bbTrackView : public trackView +{ + Q_OBJECT +public: + bbTrackView( bbTrack * _bbt, trackContainerView * _tcv ); + virtual ~bbTrackView(); + + inline nameLabel * trackLabel( void ) + { + return( m_trackLabel ); + } + + virtual bool close( void ); + + +public slots: + void clickedTrackLabel( void ); + + +private: + bbTrack * m_bbTrack; + nameLabel * m_trackLabel; + +} ; + + + #endif diff --git a/include/dummy_instrument.h b/include/dummy_instrument.h index b2bb5f8db7..78435c2271 100644 --- a/include/dummy_instrument.h +++ b/include/dummy_instrument.h @@ -33,25 +33,25 @@ class dummyInstrument : public instrument { public: - inline dummyInstrument( instrumentTrack * _instrument_track ) : + dummyInstrument( instrumentTrack * _instrument_track ) : instrument( _instrument_track, NULL ) { } - inline virtual ~dummyInstrument() + virtual ~dummyInstrument() { } - inline virtual void saveSettings( QDomDocument &, QDomElement & ) + virtual void saveSettings( QDomDocument &, QDomElement & ) { } - inline virtual void loadSettings( const QDomElement & ) + virtual void loadSettings( const QDomElement & ) { } - inline virtual QString nodeName( void ) const + virtual QString nodeName( void ) const { return( "dummyinstrument" ); } diff --git a/include/engine.h b/include/engine.h index 3750f41799..3e87bf49d5 100644 --- a/include/engine.h +++ b/include/engine.h @@ -34,11 +34,13 @@ class automationEditor; class bbEditor; +class bbTrackContainer; class projectJournal; class mainWindow; class mixer; class pianoRoll; class projectNotes; +class song; class songEditor; class ladspa2LMMS; @@ -54,11 +56,28 @@ public: return( s_hasGUI ); } + // core static mixer * getMixer( void ) { return( s_mixer ); } + static song * getSong( void ) + { + return( s_song ); + } + + static bbTrackContainer * getBBTrackContainer( void ) + { + return( s_bbTrackContainer ); + } + + static projectJournal * getProjectJournal( void ) + { + return( s_projectJournal ); + } + + // GUI static mainWindow * getMainWindow( void ) { return( s_mainWindow ); @@ -84,11 +103,6 @@ public: return( s_projectNotes ); } - static projectJournal * getProjectJournal( void ) - { - return( s_projectJournal ); - } - static automationEditor * getAutomationEditor( void ) { return( s_automationEditor ); @@ -115,14 +129,19 @@ private: static bool s_hasGUI; static float s_framesPerTact64th; + // core static mixer * s_mixer; + static song * s_song; + static bbTrackContainer * s_bbTrackContainer; + static projectJournal * s_projectJournal; + + // GUI static mainWindow * s_mainWindow; static songEditor * s_songEditor; static automationEditor * s_automationEditor; static bbEditor * s_bbEditor; static pianoRoll * s_pianoRoll; static projectNotes * s_projectNotes; - static projectJournal * s_projectJournal; static ladspa2LMMS * s_ladspaManager; static QMap s_sampleExtensions; diff --git a/include/envelope_and_lfo_parameters.h b/include/envelope_and_lfo_parameters.h index a2e5011413..c0efcd1c5d 100644 --- a/include/envelope_and_lfo_parameters.h +++ b/include/envelope_and_lfo_parameters.h @@ -1,9 +1,7 @@ /* - * envelope_and_lfo_widget.h - declaration of class envelopeAndLFOWidget which - * is used by envelope/lfo/filter-tab of - * channel-window + * envelope_and_lfo_parameters.h - class envelopeAndLFOParameters * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -25,12 +23,10 @@ */ -#ifndef _ENVELOPE_AND_LFO_WIDGET_H -#define _ENVELOPE_AND_LFO_WIDGET_H +#ifndef _ENVELOPE_AND_LFO_PARAMETERS_H +#define _ENVELOPE_AND_LFO_PARAMETERS_H #include -#include - #include "journalling_object.h" #include "automatable_model.h" @@ -38,28 +34,18 @@ #include "types.h" -class QPaintEvent; -class QPixmap; - -class automatableButtonGroup; -class envelopeTabWidget; -class knob; -class ledCheckBox; -class pixmapButton; -class tempoSyncKnob; class track; -class flpImport; - -class envelopeAndLFOWidget : public QWidget, public journallingObject +class envelopeAndLFOParameters : public model, public journallingObject { Q_OBJECT public: - envelopeAndLFOWidget( float _value_for_zero_amount, QWidget * _parent, - track * _track ); - virtual ~envelopeAndLFOWidget(); + envelopeAndLFOParameters( float _value_for_zero_amount, + track * _track, + model * _parent ); + virtual ~envelopeAndLFOParameters(); static inline float expKnobVal( float _val ) { @@ -69,7 +55,7 @@ public: static void triggerLFO( void ); static void resetLFO( void ); - void FASTCALL fillLevel( float * _buf, f_cnt_t _frame, + void fillLevel( float * _buf, f_cnt_t _frame, const f_cnt_t _release_begin, const fpp_t _frames ); @@ -79,52 +65,38 @@ public: } - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); - inline virtual QString nodeName( void ) const + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + virtual QString nodeName( void ) const { return( "el" ); } + inline f_cnt_t PAHD_Frames( void ) const + { + return( m_pahdFrames ); + } + + inline f_cnt_t releaseFrames( void ) const + { + return( m_rFrames ); + } + public slots: void updateSampleVars( void ); protected: - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - - void FASTCALL fillLFOLevel( float * _buf, f_cnt_t _frame, - const fpp_t _frames ); - - -protected slots: - void lfoUserWaveChanged( void ); + void fillLFOLevel( float * _buf, f_cnt_t _frame, const fpp_t _frames ); private: - static QPixmap * s_envGraph; - static QPixmap * s_lfoGraph; + static QVector s_EaLParametersInstances; - static QVector s_EaLWidgets; - - bool m_used; + bool m_used; - // envelope-stuff - knob * m_predelayKnob; - knob * m_attackKnob; - knob * m_holdKnob; - knob * m_decayKnob; - knob * m_sustainKnob; - knob * m_releaseKnob; - knob * m_amountKnob; - - // models floatModel m_predelayModel; floatModel m_attackModel; floatModel m_holdModel; @@ -143,18 +115,6 @@ private: sample_t * m_rEnv; - // LFO-stuff - knob * m_lfoPredelayKnob; - knob * m_lfoAttackKnob; - tempoSyncKnob * m_lfoSpeedKnob; - knob * m_lfoAmountKnob; - pixmapButton * m_userLfoBtn; - automatableButtonGroup * m_lfoWaveBtnGrp; - - ledCheckBox * m_x100Cb; - ledCheckBox * m_controlEnvAmountCb; - - // models floatModel m_lfoPredelayModel; floatModel m_lfoAttackModel; floatModel m_lfoSpeedModel; @@ -175,13 +135,14 @@ private: bool m_bad_lfoShapeData; sampleBuffer m_userWave; - enum lfoShapes + enum LfoShapes { - SIN, - TRIANGLE, - SAW, - SQUARE, - USER + SineWave, + TriangleWave, + SawWave, + SquareWave, + UserDefinedWave, + NumLfoShapes } ; sample_t lfoShapeSample( fpp_t _frame_offset ); @@ -189,8 +150,8 @@ private: - friend class envelopeTabWidget; - friend class flpImport; + friend class envelopeAndLFOView; +// friend class flpImport; } ; diff --git a/include/envelope_and_lfo_view.h b/include/envelope_and_lfo_view.h new file mode 100644 index 0000000000..199edee836 --- /dev/null +++ b/include/envelope_and_lfo_view.h @@ -0,0 +1,98 @@ +/* + * envelope_and_lfo_view.h - declaration of class envelopeAndLFOWidget which + * is used by envelope/lfo/filter-tab of + * channel-window + * + * Copyright (c) 2004-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 _ENVELOPE_AND_LFO_VIEW_H +#define _ENVELOPE_AND_LFO_VIEW_H + +#include + +#include "mv_base.h" + +class QPaintEvent; +class QPixmap; + +class envelopeAndLFOParameters; + +class automatableButtonGroup; +class knob; +class ledCheckBox; +class pixmapButton; +class tempoSyncKnob; + + + +class envelopeAndLFOView : public QWidget, public modelView +{ + Q_OBJECT +public: + envelopeAndLFOView( QWidget * _parent ); + virtual ~envelopeAndLFOView(); + + +protected: + virtual void modelChanged( void ); + + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + virtual void dropEvent( QDropEvent * _de ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void paintEvent( QPaintEvent * _pe ); + + +protected slots: + void lfoUserWaveChanged( void ); + + +private: + static QPixmap * s_envGraph; + static QPixmap * s_lfoGraph; + + envelopeAndLFOParameters * m_params; + + + // envelope-stuff + knob * m_predelayKnob; + knob * m_attackKnob; + knob * m_holdKnob; + knob * m_decayKnob; + knob * m_sustainKnob; + knob * m_releaseKnob; + knob * m_amountKnob; + + // LFO-stuff + knob * m_lfoPredelayKnob; + knob * m_lfoAttackKnob; + tempoSyncKnob * m_lfoSpeedKnob; + knob * m_lfoAmountKnob; + pixmapButton * m_userLfoBtn; + automatableButtonGroup * m_lfoWaveBtnGrp; + + ledCheckBox * m_x100Cb; + ledCheckBox * m_controlEnvAmountCb; + +} ; + +#endif diff --git a/include/file_browser.h b/include/file_browser.h index 4ed9abeed8..d2a6479c8d 100644 --- a/include/file_browser.h +++ b/include/file_browser.h @@ -173,13 +173,18 @@ public: text( 0 ) ); } - enum fileTypes + enum FileTypes { - PROJECT_FILE, PRESET_FILE, SAMPLE_FILE, MIDI_FILE, FLP_FILE, - UNKNOWN + ProjectFile, + PresetFile, + SampleFile, + MidiFile, + FlpFile, + UnknownFile, + NumFileTypes } ; - inline fileTypes type( void ) + inline FileTypes type( void ) { return( m_type ); } @@ -200,7 +205,7 @@ private: static QPixmap * s_unknownFilePixmap; QString m_path; - fileTypes m_type; + FileTypes m_type; } ; diff --git a/include/instrument_function_views.h b/include/instrument_function_views.h new file mode 100644 index 0000000000..0b3f200ffe --- /dev/null +++ b/include/instrument_function_views.h @@ -0,0 +1,91 @@ +/* + * instrument_function_views.h - views for instrument-functions-tab + * + * Copyright (c) 2004-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 _INSTRUMENT_FUNCTION_VIEWS_H +#define _INSTRUMENT_FUNCTION_VIEWS_H + +#include "mv_base.h" + + +class automatableButtonGroup; +class comboBox; +class groupBox; +class knob; +class tempoSyncKnob; + +class arpeggiator; +class chordCreator; + + + +class chordCreatorView : public QWidget, public modelView +{ +public: + chordCreatorView( chordCreator * _cc, QWidget * _parent ); + virtual ~chordCreatorView(); + + +private: + virtual void modelChanged( void ); + + chordCreator * m_cc; + + groupBox * m_chordsGroupBox; + comboBox * m_chordsComboBox; + knob * m_chordRangeKnob; + +} ; + + + + + +class arpeggiatorView : public QWidget, public modelView +{ +public: + arpeggiatorView( arpeggiator * _arp, QWidget * _parent ); + virtual ~arpeggiatorView(); + + +private: + virtual void modelChanged( void ); + + arpeggiator * m_a; + groupBox * m_arpGroupBox; + comboBox * m_arpComboBox; + knob * m_arpRangeKnob; + tempoSyncKnob * m_arpTimeKnob; + knob * m_arpGateKnob; + + QLabel * m_arpDirectionLbl; + + automatableButtonGroup * m_arpDirectionBtnGrp; + + comboBox * m_arpModeComboBox; + +} ; + + +#endif diff --git a/include/instrument_functions.h b/include/instrument_functions.h new file mode 100644 index 0000000000..fdb7794373 --- /dev/null +++ b/include/instrument_functions.h @@ -0,0 +1,141 @@ +/* + * instrument_functions.h - models for instrument-functions-tab + * + * Copyright (c) 2004-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 _INSTRUMENT_FUNCTIONS_H +#define _INSTRUMENT_FUNCTIONS_H + +#include "journalling_object.h" +#include "types.h" +#include "automatable_model.h" +#include "combobox.h" + + +class instrumentTrack; +class notePlayHandle; + + +const int MAX_CHORD_POLYPHONY = 10; + + +class chordCreator : public model, public journallingObject +{ +public: + chordCreator( instrumentTrack * _instrument_track ); + virtual ~chordCreator(); + + void processNote( notePlayHandle * _n ); + + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + + inline virtual QString nodeName( void ) const + { + return( "chordcreator" ); + } + + + static struct chord + { + const QString name; + Sint8 interval[MAX_CHORD_POLYPHONY]; + } s_chordTable[]; + + + static inline int getChordSize( chord & _c ) + { + int idx = 0; + while( _c.interval[idx] != -1 ) + { + ++idx; + } + return( idx ); + } + + +private: + boolModel m_chordsEnabledModel; + comboBoxModel m_chordsModel; + floatModel m_chordRangeModel; + + + friend class chordCreatorView; + +} ; + + + + +class arpeggiator : public model, public journallingObject +{ +public: + enum ArpDirections + { + ArpDirUp, + ArpDirDown, + ArpDirUpAndDown, + ArpDirRandom + } ; + + arpeggiator( instrumentTrack * _instrument_track ); + virtual ~arpeggiator(); + + void processNote( notePlayHandle * _n ); + + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + + inline virtual QString nodeName( void ) const + { + return( "arpeggiator" ); + } + + +private: + enum ArpModes + { + FreeMode, + SortMode, + SyncMode + } ; + + boolModel m_arpEnabledModel; + comboBoxModel m_arpModel; + floatModel m_arpRangeModel; + floatModel m_arpTimeModel; + floatModel m_arpGateModel; + intModel m_arpDirectionModel; + comboBoxModel m_arpModeModel; + + +// friend class flpImport; + friend class instrumentTrack; + friend class arpeggiatorView; + +} ; + + +#endif diff --git a/include/instrument_midi_io.h b/include/instrument_midi_io.h index 3a042f0975..131183ed8b 100644 --- a/include/instrument_midi_io.h +++ b/include/instrument_midi_io.h @@ -1,8 +1,7 @@ /* - * midi_tab_widget.h - tab-widget in channel-track-window for setting up - * MIDI-related stuff + * instrument_midi_io.h - class instrumentMidiIO * - * Copyright (c) 2005-2007 Tobias Doerffel + * Copyright (c) 2005-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -24,37 +23,33 @@ */ -#ifndef _MIDI_TAB_WIDGET_H -#define _MIDI_TAB_WIDGET_H +#ifndef _INSTRUMENT_MIDI_IO_H +#define _INSTRUMENT_MIDI_IO_H -#include +#include #include "automatable_model.h" -class QMenu; -class QPixmap; -class QAction; - class instrumentTrack; -class tabWidget; -class ledCheckBox; -class lcdSpinBox; class midiPort; -class midiTabWidget : public QWidget, public journallingObject +class instrumentMidiIO : public model, public journallingObject { Q_OBJECT public: - midiTabWidget( instrumentTrack * _channel_track, midiPort * _port ); - virtual ~midiTabWidget(); + typedef QPair descriptiveMidiPort; + typedef QList midiPortMap; + + instrumentMidiIO( instrumentTrack * _instrument_track, + midiPort * _port ); + virtual ~instrumentMidiIO(); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); - inline virtual QString nodeName( void ) const + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + virtual QString nodeName( void ) const { return( "midi" ); } @@ -71,20 +66,15 @@ protected slots: void defaultVelOutChanged( void ); void readablePortsChanged( void ); void writeablePortsChanged( void ); - void activatedReadablePort( QAction * _item ); - void activatedWriteablePort( QAction * _item ); + + void activatedReadablePort( const descriptiveMidiPort & _port ); + void activatedWriteablePort( const descriptiveMidiPort & _port ); + private: instrumentTrack * m_instrumentTrack; midiPort * m_midiPort; - tabWidget * m_setupTabWidget; - lcdSpinBox * m_inputChannelSpinBox; - lcdSpinBox * m_outputChannelSpinBox; - ledCheckBox * m_receiveCheckBox; - ledCheckBox * m_sendCheckBox; - ledCheckBox * m_defaultVelocityInCheckBox; - ledCheckBox * m_defaultVelocityOutCheckBox; intModel m_inputChannelModel; intModel m_outputChannelModel; boolModel m_receiveEnabledModel; @@ -92,10 +82,11 @@ private: boolModel m_defaultVelocityInEnabledModel; boolModel m_defaultVelocityOutEnabledModel; - QMenu * m_readablePorts; - QMenu * m_writeablePorts; + midiPortMap m_readablePorts; + midiPortMap m_writeablePorts; - friend class instrumentTrack; + + friend class instrumentMidiIOView; } ; diff --git a/include/instrument_midi_io_view.h b/include/instrument_midi_io_view.h new file mode 100644 index 0000000000..9662ebd063 --- /dev/null +++ b/include/instrument_midi_io_view.h @@ -0,0 +1,76 @@ +/* + * instrument_midi_io_view.h - tab-widget in instrument-track-window for setting + * up MIDI-related stuff + * + * Copyright (c) 2005-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 _INSTRUMENT_MIDI_IO_VIEW_H +#define _INSTRUMENT_MIDI_IO_VIEW_H + +#include + +#include "mv_base.h" + + +class QMenu; +class QAction; + +class tabWidget; +class ledCheckBox; +class lcdSpinBox; + + +class instrumentMidiIOView : public QWidget, public modelView +{ + Q_OBJECT +public: + instrumentMidiIOView( QWidget * _parent ); + virtual ~instrumentMidiIOView(); + + +protected slots: + void activatedReadablePort( QAction * _item ); + void activatedWriteablePort( QAction * _item ); + + +private: + virtual void modelChanged( void ); + + tabWidget * m_setupTabWidget; + lcdSpinBox * m_inputChannelSpinBox; + lcdSpinBox * m_outputChannelSpinBox; + ledCheckBox * m_receiveCheckBox; + ledCheckBox * m_sendCheckBox; + ledCheckBox * m_defaultVelocityInCheckBox; + ledCheckBox * m_defaultVelocityOutCheckBox; + + QMenu * m_readablePorts; + QMenu * m_writeablePorts; + + + friend class instrumentTrackWindow; + +} ; + + +#endif diff --git a/include/instrument_sound_shaping.h b/include/instrument_sound_shaping.h index 65f92cd7ec..5a8b4e622f 100644 --- a/include/instrument_sound_shaping.h +++ b/include/instrument_sound_shaping.h @@ -1,9 +1,7 @@ /* - * envelope_tab_widget.h - declaration of class envelopeTabWidget which - * provides UI- and DSP-code for using envelopes, LFOs - * and a filter + * instrument_sound_shaping.h - class instrumentSoundShaping * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -25,58 +23,44 @@ */ -#ifndef _ENVELOPE_TAB_WIDGET_H -#define _ENVELOPE_TAB_WIDGET_H - -#include +#ifndef _INSTRUMENT_SOUND_SHAPING_H +#define _INSTRUMENT_SOUND_SHAPING_H #include "mixer.h" #include "automatable_model.h" +#include "combobox.h" -class QLabel; - -class comboBoxModel; class instrumentTrack; -class comboBox; -class envelopeAndLFOWidget; -class groupBox; -class knob; +class envelopeAndLFOParameters; class notePlayHandle; -class pixmapButton; -class tabWidget; -class envelopeTabWidget : public QWidget, public journallingObject +class instrumentSoundShaping : public model, public journallingObject { - Q_OBJECT public: - envelopeTabWidget( instrumentTrack * _channel_track ); - virtual ~envelopeTabWidget(); + instrumentSoundShaping( instrumentTrack * _instrument_track ); + virtual ~instrumentSoundShaping(); - void FASTCALL processAudioBuffer( sampleFrame * _ab, - const fpp_t _frames, + void processAudioBuffer( sampleFrame * _ab, const fpp_t _frames, notePlayHandle * _n ); - enum targets + enum Targets { - VOLUME, -/* PANNING, - PITCH,*/ - CUT, - RES, - TARGET_COUNT + Volume, + Cut, + Resonance, + NumTargets } ; - f_cnt_t envFrames( const bool _only_vol = FALSE ); - f_cnt_t releaseFrames( const bool _only_vol = FALSE ); + f_cnt_t envFrames( const bool _only_vol = FALSE ) const; + f_cnt_t releaseFrames( const bool _only_vol = FALSE ) const; - float FASTCALL volumeLevel( notePlayHandle * _n, const f_cnt_t _frame ); + float volumeLevel( notePlayHandle * _n, const f_cnt_t _frame ); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { return( "eldata" ); @@ -84,23 +68,21 @@ public: private: - tabWidget * m_targetsTabWidget; - envelopeAndLFOWidget * m_envLFOWidgets[TARGET_COUNT]; + envelopeAndLFOParameters * m_envLFOParameters[NumTargets]; instrumentTrack * m_instrumentTrack; - // filter-stuff - groupBox * m_filterGroupBox; - comboBox * m_filterComboBox; - knob * m_filterCutKnob; - knob * m_filterResKnob; + boolModel m_filterEnabledModel; + comboBoxModel m_filterModel; + floatModel m_filterCutModel; + floatModel m_filterResModel; - boolModel * m_filterEnabledModel; - comboBoxModel * m_filterModel; - floatModel * m_filterCutModel; - floatModel * m_filterResModel; - friend class flpImport; + friend class instrumentSoundShapingView; } ; + +extern const QString __targetNames[instrumentSoundShaping::NumTargets][2]; + + #endif diff --git a/include/instrument_sound_shaping_view.h b/include/instrument_sound_shaping_view.h new file mode 100644 index 0000000000..1a35af9121 --- /dev/null +++ b/include/instrument_sound_shaping_view.h @@ -0,0 +1,63 @@ +/* + * instrument_sound_shaping_view.h - view for instrumentSoundShaping-class + * + * Copyright (c) 2004-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 _INSTRUMENT_SOUND_SHAPING_VIEW_H +#define _INSTRUMENT_SOUND_SHAPING_VIEW_H + +#include + +#include "instrument_sound_shaping.h" + +class envelopeAndLFOView; +class comboBox; +class groupBox; +class knob; +class tabWidget; + + +class instrumentSoundShapingView : public QWidget, public modelView +{ +public: + instrumentSoundShapingView( QWidget * _parent ); + virtual ~instrumentSoundShapingView(); + + +private: + virtual void modelChanged( void ); + + + instrumentSoundShaping * m_ss; + tabWidget * m_targetsTabWidget; + envelopeAndLFOView * m_envLFOViews[instrumentSoundShaping::NumTargets]; + + // filter-stuff + groupBox * m_filterGroupBox; + comboBox * m_filterComboBox; + knob * m_filterCutKnob; + knob * m_filterResKnob; + +} ; + +#endif diff --git a/include/instrument_track.h b/include/instrument_track.h index 3bf047f239..0d1242fd01 100644 --- a/include/instrument_track.h +++ b/include/instrument_track.h @@ -28,13 +28,16 @@ #define _INSTRUMENT_TRACK_H #include -#include #include "audio_port.h" #include "automatable_model.h" +#include "instrument_functions.h" +#include "instrument_midi_io.h" +#include "instrument_sound_shaping.h" #include "lcd_spinbox.h" #include "midi_event_processor.h" #include "mixer.h" +#include "piano_widget.h" #include "effect_chain.h" #include "surround_area.h" #include "tab_widget.h" @@ -42,23 +45,23 @@ class QLineEdit; -class arpAndChordsTabWidget; +class arpeggiatorView; +class chordCreatorView; class effectRackView; -class envelopeTabWidget; +class instrumentSoundShapingView; class fadeButton; class instrument; +class instrumentMidiIOView; class instrumentTrackButton; -class lcdSpinBox; +class instrumentTrackWindow; class midiPort; -class midiTabWidget; class notePlayHandle; -class pianoWidget; +class pluginView; class presetPreviewPlayHandle; -class surroundArea; class volumeKnob; -class instrumentTrack : public QWidget, public track, public midiEventProcessor +class instrumentTrack : public track, public midiEventProcessor { Q_OBJECT mapPropertyFromModel(int,getVolume,setVolume,m_volumeModel); @@ -66,29 +69,22 @@ public: instrumentTrack( trackContainer * _tc ); virtual ~instrumentTrack(); - inline virtual trackTypes type( void ) const - { - return( m_trackType ); - } - - // used by instrument - void FASTCALL processAudioBuffer( sampleFrame * _buf, - const fpp_t _frames, + void processAudioBuffer( sampleFrame * _buf, const fpp_t _frames, notePlayHandle * _n ); - virtual void FASTCALL processInEvent( const midiEvent & _me, + virtual void processInEvent( const midiEvent & _me, const midiTime & _time ); - virtual void FASTCALL processOutEvent( const midiEvent & _me, + virtual void processOutEvent( const midiEvent & _me, const midiTime & _time ); - f_cnt_t FASTCALL beatLen( notePlayHandle * _n ) const; + f_cnt_t beatLen( notePlayHandle * _n ) const; // for capturing note-play-events -> need that for arpeggio, // filter and so on - void FASTCALL playNote( notePlayHandle * _n, bool _try_parallelizing ); + void playNote( notePlayHandle * _n, bool _try_parallelizing ); QString instrumentName( void ) const; inline const instrument * getInstrument( void ) const @@ -96,68 +92,36 @@ public: return( m_instrument ); } - void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + void deleteNotePluginData( notePlayHandle * _n ); // name-stuff - inline const QString & name( void ) const - { - return( m_name ); - } - void FASTCALL setName( const QString & _new_name ); + virtual void setName( const QString & _new_name ); - // volume & surround-position-stuff -/* void FASTCALL setVolume( volume _new_volume ); - volume getVolume( void ) const;*/ - -// void FASTCALL setBaseNote( Uint32 _new_note, bool _modified = TRUE ); - -/* inline tones baseTone( void ) const - { - return( m_baseTone ); - } - - inline octaves baseOctave( void ) const - { - return( m_baseOctave ); - }*/ - - int FASTCALL masterKey( notePlayHandle * _n ) const; + int masterKey( notePlayHandle * _n ) const; // play everything in given frame-range - creates note-play-handles - virtual bool FASTCALL play( const midiTime & _start, - const fpp_t _frames, - const f_cnt_t _frame_base, + virtual bool play( const midiTime & _start, const fpp_t _frames, + const f_cnt_t _frame_base, Sint16 _tco_num = -1 ); + // create new view for me + virtual trackView * createView( trackContainerView * _tcv ); + // create new track-content-object = pattern - virtual trackContentObject * FASTCALL createTCO( const midiTime & - _pos ); + virtual trackContentObject * createTCO( const midiTime & _pos ); // called by track - virtual void FASTCALL saveTrackSpecificSettings( QDomDocument & _doc, + virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL loadTrackSpecificSettings( const QDomElement & - _this ); + virtual void loadTrackSpecificSettings( const QDomElement & _this ); using track::setJournalling; // load instrument whose name matches given one - instrument * FASTCALL loadInstrument( const QString & - _instrument_name ); + instrument * loadInstrument( const QString & _instrument_name ); - // parent for all internal tab-widgets - QWidget * tabWidgetParent( void ) - { - return( m_tabWidget ); - } - - pianoWidget * getPianoWidget( void ) - { - return( m_pianoWidget ); - } - inline audioPort * getAudioPort( void ) { return( &m_audioPort ); @@ -168,14 +132,146 @@ public: return( &m_baseNoteModel ); } + piano * getPiano( void ) + { + return( &m_piano ); + } + + bool arpeggiatorEnabled( void ) const + { + return( m_arpeggiator.m_arpEnabledModel.value() ); + } + + +signals: + void instrumentChanged( void ); + void newNote( void ); + void noteDone( const note & _n ); + void nameChanged( void ); + + +protected: + virtual QString nodeName( void ) const + { + return( "instrumenttrack" ); + } + // invalidates all note-play-handles linked to this instrument + void invalidateAllMyNPH( void ); + + +protected slots: + void updateBaseNote( void ); + + +private: + midiPort * m_midiPort; + audioPort m_audioPort; + + notePlayHandle * m_notes[NOTES_PER_OCTAVE * OCTAVES]; + + intModel m_baseNoteModel; + + QList m_processHandles; + + + floatModel m_volumeModel; + surroundAreaModel m_surroundAreaModel; + lcdSpinBoxModel m_effectChannelModel; + + + instrument * m_instrument; + instrumentSoundShaping m_soundShaping; + arpeggiator m_arpeggiator; + chordCreator m_chordCreator; + instrumentMidiIO m_midiIO; + + piano m_piano; + + + friend class instrumentTrackView; + friend class instrumentTrackWindow; + friend class notePlayHandle; + friend class presetPreviewPlayHandle; + friend class flpImport; + +} ; + + + + +class instrumentTrackView : public trackView +{ + Q_OBJECT +public: + instrumentTrackView( instrumentTrack * _it, trackContainerView * _tc ); + virtual ~instrumentTrackView(); + + instrumentTrackWindow * getInstrumentTrackWindow( void ) + { + return( m_window ); + } + + instrumentTrack * model( void ) + { + return( castModel() ); + } + + const instrumentTrack * model( void ) const + { + return( castModel() ); + } + + +private slots: + void activityIndicatorPressed( void ); + void activityIndicatorReleased( void ); + + void updateName( void ); + + +private: + instrumentTrackWindow * m_window; + + // widgets in track-settings-widget + volumeKnob * m_tswVolumeKnob; + fadeButton * m_tswActivityIndicator; + instrumentTrackButton * m_tswInstrumentTrackButton; + + QMenu * m_tswMidiMenu; + + + friend class instrumentTrackButton; + friend class instrumentTrackWindow; + +} ; + + + + +class instrumentTrackWindow : public QWidget, public modelView, + public journallingObjectHook +{ + Q_OBJECT +public: + instrumentTrackWindow( instrumentTrackView * _tv ); + virtual ~instrumentTrackWindow(); + + // parent for all internal tab-widgets + QWidget * tabWidgetParent( void ) + { + return( m_tabWidget ); + } + public slots: void textChanged( const QString & _new_name ); void toggledInstrumentTrackButton( bool _on ); + void updateName( void ); + void updateInstrumentView( void ); - -signals: - void noteDone( const note & _n ); + void midiInSelected( void ); + void midiOutSelected( void ); + void midiConfigChanged( bool ); protected: @@ -185,40 +281,19 @@ protected: virtual void dropEvent( QDropEvent * _de ); virtual void focusInEvent( QFocusEvent * _fe ); - inline virtual QString nodeName( void ) const - { - return( "instrumenttrack" ); - } - // invalidates all note-play-handles linked to this instrument - void invalidateAllMyNPH( void ); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); + virtual void loadSettings( const QDomElement & _this ); protected slots: void saveSettingsBtnClicked( void ); - void activityIndicatorPressed( void ); - void activityIndicatorReleased( void ); - void midiInSelected( void ); - void midiOutSelected( void ); - void midiConfigChanged( bool ); - - void updateBaseNote( void ); private: - trackTypes m_trackType; - - midiPort * m_midiPort; - - audioPort m_audioPort; - - - notePlayHandle * m_notes[NOTES_PER_OCTAVE * OCTAVES]; - - - intModel m_baseNoteModel; - - QList m_processHandles; + virtual void modelChanged( void ); + instrumentTrack * m_track; + instrumentTrackView * m_itv; // widgets on the top of an instrument-track-window tabWidget * m_generalSettingsWidget; @@ -228,44 +303,23 @@ private: lcdSpinBox * m_effectChannelNumber; QPushButton * m_saveSettingsBtn; - floatModel m_volumeModel; - surroundAreaModel m_surroundAreaModel; - lcdSpinBoxModel m_effectChannelModel; - // tab-widget with all children tabWidget * m_tabWidget; - instrument * m_instrument; - envelopeTabWidget * m_envWidget; - arpAndChordsTabWidget * m_arpWidget; - midiTabWidget * m_midiWidget; - pluginView * m_instrumentView; - effectRackView * m_effectRack; - -// effectChain m_effects; + instrumentSoundShapingView * m_ssView; + chordCreatorView * m_chordView; + arpeggiatorView * m_arpView; + instrumentMidiIOView * m_midiView; + effectRackView * m_effectView; // test-piano at the bottom of every instrument-settings-window - pianoWidget * m_pianoWidget; + pianoView * m_pianoView; - - // widgets in track-settings-widget - volumeKnob * m_tswVolumeKnob; - fadeButton * m_tswActivityIndicator; - instrumentTrackButton * m_tswInstrumentTrackButton; - - QMenu * m_tswMidiMenu; QAction * m_midiInputAction; QAction * m_midiOutputAction; friend class instrumentTrackButton; - friend class notePlayHandle; - friend class presetPreviewPlayHandle; - friend class flpImport; - -/* // base-tone stuff - void FASTCALL setBaseTone( tones _new_tone ); - void FASTCALL setBaseOctave( octaves _new_octave );*/ } ; @@ -275,14 +329,14 @@ private: class instrumentTrackButton : public QPushButton { public: - instrumentTrackButton( instrumentTrack * _instrument_track ); + instrumentTrackButton( instrumentTrackView * _instrument_track_view ); virtual ~instrumentTrackButton(); protected: // since we want to draw a special label (instrument- and instrument- // name) on our button, we have to re-implement this for doing so - virtual void drawButtonLabel( QPainter * _p ); + virtual void paintEvent( QPaintEvent * _pe ); // allow drops on this button - we simply forward them to // instrument-track @@ -291,7 +345,7 @@ protected: private: - instrumentTrack * m_instrumentTrack; + instrumentTrackView * m_instrumentTrackView; } ; diff --git a/include/journalling_object.h b/include/journalling_object.h index a0316548ea..ced51b774b 100644 --- a/include/journalling_object.h +++ b/include/journalling_object.h @@ -1,7 +1,7 @@ /* * journalling_object.h - declaration of class journallingObject * - * Copyright (c) 2006-2007 Tobias Doerffel + * Copyright (c) 2006-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -37,15 +37,15 @@ #include - class QDomDocument; class QDomElement; -typedef Uint32 t_action_id; +typedef uint32_t t_action_id; class journallingObject; +class journallingObjectHook; class journalEntry @@ -98,7 +98,6 @@ private: typedef QVector journalEntryVector; - class journallingObject { public: @@ -138,10 +137,10 @@ public: m_journalling = m_journallingStateStack.pop(); } - virtual QDomElement FASTCALL saveState( QDomDocument & _doc, + virtual QDomElement saveState( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL restoreState( const QDomElement & _this ); + virtual void restoreState( const QDomElement & _this ); // to be implemented by actual object @@ -164,18 +163,23 @@ public: return( old_journalling ); } + void setHook( journallingObjectHook * _hook ); + + journallingObjectHook * getHook( void ) + { + return( m_hook ); + } protected: void addJournalEntry( const journalEntry & _je ); // to be implemented by sub-objects - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _this ) + virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ) { } - virtual void FASTCALL loadSettings( const QDomElement & _this ) + virtual void loadSettings( const QDomElement & _this ) { } @@ -201,9 +205,36 @@ private: QStack m_journallingStateStack; + journallingObjectHook * m_hook; + } ; +class journallingObjectHook +{ +public: + journallingObjectHook() : + m_hookedIn( NULL ) + { + } + virtual ~journallingObjectHook() + { + if( m_hookedIn != NULL ) + { + m_hookedIn->setHook( NULL ); + } + } + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ) = 0; + virtual void loadSettings( const QDomElement & _this ) = 0; + +private: + journallingObject * m_hookedIn; + + friend class journallingObject; + +} ; + #endif diff --git a/include/main_window.h b/include/main_window.h index a9550e5844..95bc66409a 100644 --- a/include/main_window.h +++ b/include/main_window.h @@ -58,7 +58,7 @@ public: int addWidgetToToolBar( QWidget * _w, int _row = -1, int _col = -1 ); void addSpacingToToolBar( int _size ); - void resetWindowTitle( bool _modified = FALSE ); + void resetWindowTitle( void ); // every function that replaces current file (e.g. creates new file, @@ -158,8 +158,6 @@ private: QMenu * m_toolsMenu; QList m_tools; - bool m_modified; - friend class engine; diff --git a/include/mmp.h b/include/mmp.h index 97d1eb1de4..508f6bb63e 100644 --- a/include/mmp.h +++ b/include/mmp.h @@ -1,7 +1,7 @@ /* * mmp.h - class for reading and writing multimedia-project-files * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -34,27 +34,27 @@ class multimediaProject : public QDomDocument { public: - enum projectTypes + enum ProjectTypes { - UNKNOWN, - SONG_PROJECT, - SONG_PROJECT_TEMPLATE, - INSTRUMENT_TRACK_SETTINGS, - DRAG_N_DROP_DATA, - CLIPBOARD_DATA, - JOURNAL_DATA, - EFFECT_SETTINGS, - VIDEO_PROJECT, // might come later... - BURN_PROJECT, // might come later... - PLAYLIST, // might come later... - PROJ_TYPE_COUNT + UnknownType, + SongProject, + SongProjectTemplate, + InstrumentTrackSettings, + DragNDropData, + ClipboardData, + JournalData, + EffectSettings, + VideoProject, // might come later... + BurnProject, // might come later... + Playlist, // might come later... + NumProjectTypes } ; multimediaProject( const QString & _in_file_name, bool _is_filename = TRUE, bool _upgrade = TRUE ); - multimediaProject( projectTypes _project_type ); + multimediaProject( ProjectTypes _project_type ); ~multimediaProject(); QString nameWithExtension( const QString & _fn ) const; @@ -70,17 +70,17 @@ public: return( m_head ); } - inline projectTypes type( void ) const + inline ProjectTypes type( void ) const { return( m_type ); } - static projectTypes typeOfFile( const QString & _fn ); + static ProjectTypes typeOfFile( const QString & _fn ); private: - static projectTypes type( const QString & _type_name ); - static QString typeName( projectTypes _project_type ); + static ProjectTypes type( const QString & _type_name ); + static QString typeName( ProjectTypes _project_type ); void cleanMetaNodes( QDomElement _de ); @@ -89,14 +89,14 @@ private: struct typeDescStruct { - projectTypes m_type; + ProjectTypes m_type; QString m_name; } ; - static typeDescStruct s_types[PROJ_TYPE_COUNT]; + static typeDescStruct s_types[NumProjectTypes]; QDomElement m_content; QDomElement m_head; - projectTypes m_type; + ProjectTypes m_type; } ; diff --git a/include/mv_base.h b/include/mv_base.h index 7e38aa73ed..ee3ac4c901 100644 --- a/include/mv_base.h +++ b/include/mv_base.h @@ -54,7 +54,6 @@ public: private: bool m_defaultConstructed; - signals: // emitted if actual data of the model (e.g. values) have changed void dataChanged( void ); diff --git a/include/name_label.h b/include/name_label.h index 099d4dfe81..04a3ae3603 100644 --- a/include/name_label.h +++ b/include/name_label.h @@ -2,7 +2,7 @@ * name_label.h - class nameLabel, a label which is renamable by * double-clicking it * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -58,7 +58,6 @@ public slots: signals: void clicked( void ); - void nameChanged( void ); void nameChanged( const QString & _new_name ); void pixmapChanged( void ); diff --git a/include/pattern.h b/include/pattern.h index b42f27b845..ecc6a15860 100644 --- a/include/pattern.h +++ b/include/pattern.h @@ -2,7 +2,7 @@ * pattern.h - declaration of class pattern, which contains all informations * about a pattern * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -56,12 +56,13 @@ class pattern : public trackContentObject { Q_OBJECT public: - enum patternTypes + enum PatternTypes { - BEAT_PATTERN, MELODY_PATTERN/*, AUTOMATION_PATTERN*/ + BeatPattern, + MelodyPattern } ; - pattern( instrumentTrack * _channel_track ); + pattern( instrumentTrack * _instrument_track ); pattern( const pattern & _pat_to_copy ); virtual ~pattern(); @@ -70,13 +71,12 @@ public: virtual midiTime length( void ) const; - note * FASTCALL addNote( const note & _new_note, - const bool _quant_pos = TRUE ); + note * addNote( const note & _new_note, const bool _quant_pos = TRUE ); - void FASTCALL removeNote( const note * _note_to_del ); + void removeNote( const note * _note_to_del ); - note * FASTCALL rearrangeNote( const note * _note_to_proc, - const bool _quant_pos = TRUE ); + note * rearrangeNote( const note * _note_to_proc, + const bool _quant_pos = TRUE ); void clearNotes( void ); @@ -86,11 +86,11 @@ public: } // pattern-type stuff - inline patternTypes type( void ) const + inline PatternTypes type( void ) const { return( m_patternType ); } - void FASTCALL setType( patternTypes _new_pattern_type ); + void setType( PatternTypes _new_pattern_type ); void checkType( void ); @@ -103,7 +103,7 @@ public: inline void setName( const QString & _name ) { m_name = _name; - update(); + emit dataChanged(); } @@ -124,9 +124,8 @@ public: } // settings-management - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { return( "pattern" ); @@ -140,57 +139,32 @@ public: bool empty( void ); -public slots: - virtual void update( void ); - - -protected slots: - void openInPianoRoll( bool _c ); - void openInPianoRoll( void ); - - void clear( void ); - void resetName( void ); - void changeName( void ); - void freeze( void ); - void unfreeze( void ); - void abortFreeze( void ); - - void addSteps( QAction * _item ); - void removeSteps( QAction * _item ); void addSteps( int _n ); void removeSteps( int _n ); + virtual trackContentObjectView * createView( trackView * _tv ); + + + using model::dataChanged; + protected: - virtual void constructContextMenu( QMenu * ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - virtual void resizeEvent( QResizeEvent * _re ) - { - m_needsUpdate = TRUE; - trackContentObject::resizeEvent( _re ); - } - virtual void wheelEvent( QWheelEvent * _we ); - void ensureBeatNotes( void ); void updateBBTrack( void ); + void abortFreeze( void ); + + +protected slots: + void clear( void ); + void freeze( void ); + void unfreeze( void ); + private: - static QPixmap * s_stepBtnOn; - static QPixmap * s_stepBtnOverlay; - static QPixmap * s_stepBtnOff; - static QPixmap * s_stepBtnOffLight; - static QPixmap * s_frozen; - - QPixmap m_paintPixmap; - bool m_needsUpdate; - - // general stuff instrumentTrack * m_instrumentTrack; - patternTypes m_patternType; + PatternTypes m_patternType; QString m_name; // data-stuff @@ -203,25 +177,77 @@ private: volatile bool m_freezeAborted; - // as in Qt4 QThread is inherits from QObject and our base - // trackContentObject is a QWidget (=QObject), we cannot inherit from - // QThread. That's why we have to put pattern-freezing into separate - // thread-class -> patternFreezeThread + friend class patternView; friend class patternFreezeThread; } ; +class patternView : public trackContentObjectView +{ + Q_OBJECT +public: + patternView( pattern * _pattern, trackView * _parent ); + virtual ~patternView(); + + +public slots: + virtual void update( void ); + + +protected slots: + void openInPianoRoll( bool _c ); + void openInPianoRoll( void ); + + void resetName( void ); + void changeName( void ); + + void addSteps( QAction * _item ); + void removeSteps( QAction * _item ); + + +protected: + virtual void constructContextMenu( QMenu * ); + virtual void mouseDoubleClickEvent( QMouseEvent * _me ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void paintEvent( QPaintEvent * _pe ); + virtual void resizeEvent( QResizeEvent * _re ) + { + m_needsUpdate = TRUE; + trackContentObjectView::resizeEvent( _re ); + } + virtual void wheelEvent( QWheelEvent * _we ); + + +private: + static QPixmap * s_stepBtnOn; + static QPixmap * s_stepBtnOverlay; + static QPixmap * s_stepBtnOff; + static QPixmap * s_stepBtnOffLight; + static QPixmap * s_frozen; + + pattern * m_pat; + QPixmap m_paintPixmap; + bool m_needsUpdate; + +} ; + + + + +// TODO: move to own header-files +// + class patternFreezeStatusDialog : public QDialog { Q_OBJECT public: patternFreezeStatusDialog( QThread * _thread ); - ~patternFreezeStatusDialog(); + virtual ~patternFreezeStatusDialog(); - void FASTCALL setProgress( int _p ); + void setProgress( int _p ); protected: diff --git a/include/piano_widget.h b/include/piano_widget.h index 9f6668db2f..e3544e8efc 100644 --- a/include/piano_widget.h +++ b/include/piano_widget.h @@ -1,8 +1,8 @@ /* - * piano_widget.h - declaration of class pianoWidget, a widget which provides + * piano_widget.h - declaration of class pianoView, a widget which provides * an interactive piano/keyboard-widget * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -37,35 +37,54 @@ class instrumentTrack; -class knob; +class instrumentTrackView; class notePlayHandle; -enum keyTypes +enum KeyTypes { - WHITE_KEY, - BLACK_KEY + WhiteKey, + BlackKey } ; -class pianoWidget : public QWidget +class piano : public model +{ +public: + piano( instrumentTrack * _it ); + virtual ~piano(); + + void setKeyState( int _key, bool _on = FALSE ); + static int getKeyFromKeycode( int _kc ); + + +private: + instrumentTrack * m_instrumentTrack; + bool m_pressedKeys[NOTES_PER_OCTAVE * OCTAVES]; + + + friend class pianoView; + +} ; + + + +class pianoView : public QWidget, public modelView { Q_OBJECT public: - pianoWidget( instrumentTrack * _channel_track ); - virtual ~pianoWidget(); + pianoView( QWidget * _parent ); + virtual ~pianoView(); - void setKeyState( int _key, bool _on = FALSE ); +protected: + virtual void modelChanged( void ); virtual void keyPressEvent( QKeyEvent * ke ); virtual void keyReleaseEvent( QKeyEvent * ke ); #ifndef BUILD_WIN32 virtual bool x11Event( XEvent * _xe ); #endif - -protected: virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void customEvent( QEvent * ); virtual void paintEvent( QPaintEvent * ); virtual void mousePressEvent( QMouseEvent * me ); virtual void mouseReleaseEvent( QMouseEvent * me ); @@ -74,19 +93,17 @@ protected: private: - int FASTCALL getKeyFromMouse( const QPoint & _p ) const; - int FASTCALL getKeyFromKeyboard( int _k ) const; - int FASTCALL getKeyX( int _key_num ) const; + int getKeyFromMouse( const QPoint & _p ) const; + int getKeyX( int _key_num ) const; static QPixmap * s_whiteKeyPm; static QPixmap * s_blackKeyPm; static QPixmap * s_whiteKeyPressedPm; static QPixmap * s_blackKeyPressedPm; - - bool m_pressedKeys[NOTES_PER_OCTAVE * OCTAVES]; + + piano * m_piano; QScrollBar * m_pianoScroll; - instrumentTrack * m_instrumentTrack; tones m_startTone; // first key when drawing octaves m_startOctave; @@ -94,7 +111,6 @@ private: unsigned int m_keyCode; - private slots: void pianoScrolled( int _new_pos ); diff --git a/include/sample_track.h b/include/sample_track.h index 507f5e3327..0502a908c6 100644 --- a/include/sample_track.h +++ b/include/sample_track.h @@ -47,12 +47,12 @@ public: sampleTCO( track * _track ); virtual ~sampleTCO(); - virtual void FASTCALL changeLength( const midiTime & _length ); + virtual void changeLength( const midiTime & _length ); const QString & sampleFile( void ) const; - virtual void FASTCALL saveSettings( QDomDocument & _doc, + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); + virtual void loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { return( "sampletco" ); @@ -110,26 +110,23 @@ private: -class sampleTrack : public QObject, public track +class sampleTrack : public track { Q_OBJECT public: sampleTrack( trackContainer * _tc ); virtual ~sampleTrack(); - virtual trackTypes type( void ) const; - virtual bool FASTCALL play( const midiTime & _start, - const fpp_t _frames, + virtual bool play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _frame_base, Sint16 _tco_num = -1 ); - virtual trackContentObject * FASTCALL createTCO( const midiTime & - _pos ); + virtual trackView * createView( trackContainerView * _tcv ); + virtual trackContentObject * createTCO( const midiTime & _pos ); - virtual void FASTCALL saveTrackSpecificSettings( QDomDocument & _doc, + virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void FASTCALL loadTrackSpecificSettings( const QDomElement & - _this ); + virtual void loadTrackSpecificSettings( const QDomElement & _this ); inline audioPort * getAudioPort( void ) { @@ -143,13 +140,30 @@ public: private: - effectLabel * m_trackLabel; audioPort m_audioPort; - - volumeKnob * m_volumeKnob; knobModel m_volumeModel; + + friend class sampleTrackView; + } ; + +class sampleTrackView : public track +{ +public: + sampleTrackView( sampleTrack * _track, trackContainerView * _tcv ); + virtual ~sampleTrackView(); + + +private: + effectLabel * m_trackLabel; + + volumeKnob * m_volumeKnob; + +} ; + + + #endif diff --git a/include/song.h b/include/song.h new file mode 100644 index 0000000000..a9bf070e58 --- /dev/null +++ b/include/song.h @@ -0,0 +1,270 @@ +/* + * song.h - class song - the root of the model-tree + * + * Copyright (c) 2004-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 _SONG_H +#define _SONG_H + +#include "track_container.h" +#include "automatable_model.h" +#include "automatable_slider.h" +#include "lcd_spinbox.h" + + +class pattern; +class timeLine; + + +const bpm_t MIN_BPM = 10; +const bpm_t DEFAULT_BPM = 140; +const bpm_t MAX_BPM = 999; +const Uint16 MAX_SONG_LENGTH = 9999; + + +class song : public trackContainer +{ + Q_OBJECT + mapPropertyFromModel(int,masterPitch,setMasterPitch,m_masterPitchModel); + mapPropertyFromModel(int,masterVolume,setMasterVolume, + m_masterVolumeModel); +public: + enum PlayModes + { + Mode_PlaySong, + Mode_PlayTrack, + Mode_PlayBB, + Mode_PlayPattern, + Mode_PlayAutomationPattern, + Mode_Count + } ; + + + class playPos : public midiTime + { + public: + playPos( Sint32 _abs = 0 ) : + midiTime( _abs ), + m_timeLine( NULL ), + m_timeLineUpdate( TRUE ), + m_currentFrame( 0.0f ) + { + } + inline void setCurrentFrame( const float _f ) + { + m_currentFrame = _f; + } + inline float currentFrame( void ) const + { + return( m_currentFrame ); + } + timeLine * m_timeLine; + bool m_timeLineUpdate; + + private: + float m_currentFrame; + + } ; + + + + void processNextBuffer( void ); + + + inline bool paused( void ) const + { + return( m_paused ); + } + + inline bool playing( void ) const + { + return( m_playing && m_exporting == FALSE ); + } + + inline bool exporting( void ) const + { + return( m_exporting ); + } + + bool realTimeTask( void ) const; + + inline bool exportDone( void ) const + { + return( m_exporting == TRUE && + m_playPos[Mode_PlaySong].getTact() >= + lengthInTacts() + 1 ); + } + + inline PlayModes playMode( void ) const + { + return( m_playMode ); + } + + inline playPos & getPlayPos( PlayModes _pm ) + { + return( m_playPos[_pm] ); + } + + tact lengthInTacts( void ) const; + + + bpm_t getTempo( void ); + virtual automationPattern * tempoAutomationPattern( void ); + + + // file management + void createNewProject( void ); + void createNewProjectFromTemplate( const QString & _template ); + void loadProject( const QString & _file_name ); + bool saveProject( void ); + bool saveProjectAs( const QString & _file_name ); + inline const QString & projectFileName( void ) const + { + return( m_fileName ); + } + inline bool isLoadingProject( void ) const + { + return( m_loadingProject ); + } + inline bool isModified( void ) const + { + return( m_modified ); + } + + inline virtual QString nodeName( void ) const + { + return( "song" ); + } + + virtual inline bool fixedTCOs( void ) const + { + return( FALSE ); + } + + +public slots: + void play( void ); + void stop( void ); + void playTrack( track * _trackToPlay ); + void playBB( void ); + void playPattern( pattern * _patternToPlay, bool _loop = TRUE ); + void pause( void ); + void resumeFromPause( void ); + + void importProject( void ); + void exportProject( void ); + + void startExport( void ); + void stopExport( void ); + + + void setModified( void ); + + void clearProject( void ); + + +private slots: + void insertBar( void ); + void removeBar( void ); + void addBBTrack( void ); + void addSampleTrack( void ); + + void setTempo( void ); + + void masterVolumeChanged( void ); + + void doActions( void ); + + void updateFramesPerTact64th( void ); + + + +private: + song( void ); + song( const song & ); + virtual ~song(); + + + inline tact currentTact( void ) const + { + return( m_playPos[m_playMode].getTact() ); + } + + midiTime length( void ) const; + inline tact64th currentTact64th( void ) const + { + return( m_playPos[m_playMode].getTact64th() ); + } + void setPlayPos( tact _tact_num, tact64th _t_64th, PlayModes + _play_mode ); + + + + track * m_automationTrack; + + lcdSpinBoxModel m_tempoModel; + sliderModel m_masterVolumeModel; + sliderModel m_masterPitchModel; + + + QString m_fileName; + QString m_oldFileName; + bool m_modified; + + volatile bool m_exporting; + volatile bool m_playing; + volatile bool m_paused; + + bool m_loadingProject; + + PlayModes m_playMode; + playPos m_playPos[Mode_Count]; + + track * m_trackToPlay; + pattern * m_patternToPlay; + bool m_loopPattern; + + + enum Actions + { + ActionStop, + ActionPlaySong, + ActionPlayTrack, + ActionPlayBB, + ActionPlayPattern, + ActionPause, + ActionResumeFromPause + } ; + QVector m_actions; + + + friend class engine; + friend class songEditor; + +signals: + void tempoChanged( bpm_t _new_bpm ); + +} ; + + +#endif diff --git a/include/song_editor.h b/include/song_editor.h index 592cd82e6c..f6bf430bab 100644 --- a/include/song_editor.h +++ b/include/song_editor.h @@ -2,7 +2,7 @@ * song_editor.h - declaration of class songEditor, a window where you can * setup your songs * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -36,166 +36,24 @@ class QLabel; class QScrollBar; class comboBox; -class pattern; +class song; class textFloat; -class timeLine; class toolButton; -const bpm_t MIN_BPM = 10; -const bpm_t DEFAULT_BPM = 140; -const bpm_t MAX_BPM = 999; -const Uint16 MAX_SONG_LENGTH = 9999; - -class songEditor : public trackContainer +class songEditor : public trackContainerView { Q_OBJECT - mapPropertyFromModel(int,masterPitch,setMasterPitch,m_masterPitchModel); - mapPropertyFromModel(int,masterVolume,setMasterVolume,m_masterVolumeModel); public: - enum playModes - { - PLAY_SONG, - PLAY_TRACK, - PLAY_BB, - PLAY_PATTERN, - PLAY_AUTOMATION_PATTERN, - PLAY_MODE_CNT - } ; + songEditor( song * _song ); + virtual ~songEditor(); - class playPos : public midiTime - { - public: - playPos( Sint32 _abs = 0 ) : - midiTime( _abs ), - m_timeLine( NULL ), - m_timeLineUpdate( TRUE ), - m_currentFrame( 0.0f ) - { - } - inline void setCurrentFrame( const float _f ) - { - m_currentFrame = _f; - } - inline float currentFrame( void ) const - { - return( m_currentFrame ); - } - timeLine * m_timeLine; - bool m_timeLineUpdate; - - private: - float m_currentFrame; - } ; - - - - void processNextBuffer( void ); - - - inline bool paused( void ) const - { - return( m_paused ); - } - - inline bool playing( void ) const - { - return( m_playing && m_exporting == FALSE ); - } - - inline bool exporting( void ) const - { - return( m_exporting ); - } - - bool realTimeTask( void ) const; - - inline bool exportDone( void ) const - { - return( m_exporting == TRUE && - m_playPos[PLAY_SONG].getTact() >= lengthInTacts() + 1 ); - } - - inline playModes playMode( void ) const - { - return( m_playMode ); - } - - inline playPos & getPlayPos( playModes _pm ) - { - return( m_playPos[_pm] ); - } - - tact lengthInTacts( void ) const; - - - bpm_t getTempo( void ); - virtual automationPattern * tempoAutomationPattern( void ); - - - // file management - void createNewProject( void ); - void FASTCALL createNewProjectFromTemplate( const QString & _template ); - void FASTCALL loadProject( const QString & _file_name ); - bool saveProject( void ); - bool FASTCALL saveProjectAs( const QString & _file_name ); - inline const QString & projectFileName( void ) const - { - return( m_fileName ); - } - - inline virtual QString nodeName( void ) const - { - return( "songeditor" ); - } - - virtual inline bool fixedTCOs( void ) const - { - return( FALSE ); - } - - -public slots: - void play( void ); - void stop( void ); - void playTrack( track * _trackToPlay ); - void playBB( void ); - void playPattern( pattern * _patternToPlay, bool _loop = TRUE ); - void pause( void ); - void resumeFromPause( void ); - - void importProject( void ); - void exportProject( void ); - - void startExport( void ); - void stopExport( void ); - - - void setModified( void ); - - void clearProject( void ); - - -protected: - virtual void keyPressEvent( QKeyEvent * _ke ); - virtual void wheelEvent( QWheelEvent * _we ); - virtual void paintEvent( QPaintEvent * _pe ); - - virtual bool allowRubberband( void ) const; - - -protected slots: - void insertBar( void ); - void removeBar( void ); - void addBBTrack( void ); - void addSampleTrack( void ); +private slots: void scrolled( int _new_pos ); void updateTimeLinePosition( void ); - void setTempo( void ); - void masterVolumeChanged( int _new_val ); void masterVolumePressed( void ); void masterVolumeMoved( int _new_val ); @@ -209,31 +67,18 @@ protected slots: void zoomingChanged( void ); - void doActions( void ); - private: - songEditor( void ); - songEditor( const songEditor & ); - virtual ~songEditor(); + virtual void keyPressEvent( QKeyEvent * _ke ); + virtual void wheelEvent( QWheelEvent * _we ); + virtual void paintEvent( QPaintEvent * _pe ); + + virtual bool allowRubberband( void ) const; + +// virtual void modelChanged( void ); - inline tact currentTact( void ) const - { - return( m_playPos[m_playMode].getTact() ); - } - - midiTime length( void ) const; - inline tact64th currentTact64th( void ) const - { - return( m_playPos[m_playMode].getTact64th() ); - } - void FASTCALL setPlayPos( tact _tact_num, tact64th _t_64th, playModes - _play_mode ); - - - - track * m_automationTrack; + song * m_s; QScrollBar * m_leftRightScroll; @@ -242,12 +87,9 @@ private: toolButton * m_playButton; toolButton * m_stopButton; lcdSpinBox * m_tempoSpinBox; - lcdSpinBoxModel m_tempoModel; automatableSlider * m_masterVolumeSlider; automatableSlider * m_masterPitchSlider; - sliderModel m_masterVolumeModel; - sliderModel m_masterPitchModel; textFloat * m_mvsStatus; textFloat * m_mpsStatus; @@ -261,45 +103,10 @@ private: comboBox * m_zoomingComboBox; - QString m_fileName; - QString m_oldFileName; - - volatile bool m_exporting; - volatile bool m_playing; - volatile bool m_paused; - - bool m_loadingProject; - - playModes m_playMode; - playPos m_playPos[PLAY_MODE_CNT]; - - track * m_trackToPlay; - pattern * m_patternToPlay; - bool m_loopPattern; - bool m_scrollBack; - - - enum ACTIONS - { - ACT_STOP_PLAY, ACT_PLAY_SONG, ACT_PLAY_TRACK, ACT_PLAY_BB, - ACT_PLAY_PATTERN, ACT_PAUSE, ACT_RESUME_FROM_PAUSE - } ; - QVector m_actions; - - - friend class engine; - - -private slots: - void updateFramesPerTact64th( void ); - - -signals: - void tempoChanged( bpm_t _new_bpm ); - } ; + #endif diff --git a/include/timeline.h b/include/timeline.h index d100146f06..9a7c8ef5ff 100644 --- a/include/timeline.h +++ b/include/timeline.h @@ -1,7 +1,7 @@ /* * timeline.h - class timeLine, representing a time-line with position marker * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -28,7 +28,7 @@ #include -#include "song_editor.h" +#include "song.h" class QPixmap; @@ -40,39 +40,43 @@ class timeLine : public QWidget, public journallingObject { Q_OBJECT public: - enum autoScrollStates + enum AutoScrollStates { - AUTOSCROLL_ENABLED, AUTOSCROLL_DISABLED + AutoScrollEnabled, + AutoScrollDisabled } ; - enum loopPointStates + enum LoopPointStates { - LOOP_POINTS_DISABLED, LOOP_POINTS_ENABLED + LoopPointsDisabled, + LoopPointsEnabled } ; - enum behaviourAtStopStates + enum BehaviourAtStopStates { - BACK_TO_ZERO, BACK_TO_START, KEEP_STOP_POSITION + BackToZero, + BackToStart, + KeepStopPosition } ; - timeLine( int _xoff, int _yoff, float _ppt, songEditor::playPos & _pos, + timeLine( int _xoff, int _yoff, float _ppt, song::playPos & _pos, const midiTime & _begin, QWidget * _parent ); virtual ~timeLine(); - inline songEditor::playPos & pos( void ) + inline song::playPos & pos( void ) { return( m_pos ); } - behaviourAtStopStates behaviourAtStop( void ) const + BehaviourAtStopStates behaviourAtStop( void ) const { return( m_behaviourAtStop ); } bool loopPointsEnabled( void ) const { - return( m_loopPoints == LOOP_POINTS_ENABLED ); + return( m_loopPoints == LoopPointsEnabled ); } inline const midiTime & loopBegin( void ) const @@ -105,9 +109,8 @@ public: void addToolButtons( QWidget * _tool_bar ); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { return( "timeline" ); @@ -145,16 +148,16 @@ private: static QPixmap * s_loopPointPixmap; static QPixmap * s_loopPointDisabledPixmap; - autoScrollStates m_autoScroll; - loopPointStates m_loopPoints; - behaviourAtStopStates m_behaviourAtStop; + AutoScrollStates m_autoScroll; + LoopPointStates m_loopPoints; + BehaviourAtStopStates m_behaviourAtStop; bool m_changedPosition; int m_xOffset; int m_posMarkerX; float m_ppt; - songEditor::playPos & m_pos; + song::playPos & m_pos; const midiTime & m_begin; midiTime m_loopPos[2]; @@ -166,7 +169,10 @@ private: enum actions { - NONE, MOVE_POS_MARKER, MOVE_LOOP_BEGIN, MOVE_LOOP_END + NoAction, + MovePositionMarker, + MoveLoopBegin, + MoveLoopEnd } m_action; int m_moveXOff; diff --git a/include/track.h b/include/track.h index b8bd94e648..0d2fc2d40e 100644 --- a/include/track.h +++ b/include/track.h @@ -2,7 +2,7 @@ * track.h - declaration of classes concerning tracks -> neccessary for all * track-like objects (beat/bassline, sample-track...) * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -44,6 +44,7 @@ #include "midi_time.h" #include "rubberband.h" #include "journalling_object.h" +#include "automatable_model.h" class QMenu; @@ -54,26 +55,27 @@ class bbTrack; class pixmapButton; class textFloat; class track; +class trackContentObjectView; class trackContainer; +class trackContainerView; class trackContentWidget; -class trackWidget; +class trackView; typedef QWidget trackSettingsWidget; -const Uint16 DEFAULT_SETTINGS_WIDGET_WIDTH = 224; -const Uint16 TRACK_OP_WIDTH = 70; -const Uint16 TCO_BORDER_WIDTH = 1; +const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224; +const int TRACK_OP_WIDTH = 70; +const int TCO_BORDER_WIDTH = 1; -class trackContentObject : public selectableObject, - public journallingObject +class trackContentObject : public model, public journallingObject { Q_OBJECT public: trackContentObject( track * _track ); - trackContentObject( const trackContentObject & _copy ); +// trackContentObject( const trackContentObject & _copy ); virtual ~trackContentObject(); inline track * getTrack( void ) { @@ -94,17 +96,71 @@ public: bool muted( void ) const { - return( m_muted ); + return( m_mutedModel.value() ); } + virtual void movePosition( const midiTime & _pos ); + virtual void changeLength( const midiTime & _length ); + + virtual trackContentObjectView * createView( trackView * _tv ) = 0; + + + +protected: + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); + + +protected slots: + void cut( void ); + void copy( void ); + void paste( void ); + void toggleMute( void ); + + +signals: + void lengthChanged( void ); + void positionChanged( void ); + + +private: + enum Actions + { + NoAction, + Move, + Resize + } ; + + track * m_track; + midiTime m_startPosition; + midiTime m_length; + + boolModel m_mutedModel; + + + friend class trackContentObjectView; + +} ; + + + +class trackContentObjectView : public selectableObject, public modelView +{ + Q_OBJECT +public: + trackContentObjectView( trackContentObject * _tco, trackView * _tv ); + virtual ~trackContentObjectView(); + bool fixedTCOs( void ); - virtual void FASTCALL movePosition( const midiTime & _pos ); - virtual void FASTCALL changeLength( const midiTime & _length ); + inline trackContentObject * getTrackContentObject( void ) + { + return( m_tco ); + } public slots: - virtual void close( void ); + virtual bool close( void ); protected: @@ -123,34 +179,34 @@ protected: void setAutoResizeEnabled( bool _e = FALSE ); float pixelsPerTact( void ); - virtual void undoStep( journalEntry & _je ); - virtual void redoStep( journalEntry & _je ); + inline trackView * getTrackView( void ) + { + return( m_trackView ); + } protected slots: - void cut( void ); - void copy( void ); - void paste( void ); - void toggleMute( void ); + void updateLength( void ); + void updatePosition( void ); private: - enum actions + enum Actions { - NONE, MOVE, MOVE_SELECTION, RESIZE + NoAction, + Move, + MoveSelection, + Resize } ; static textFloat * s_textFloat; - track * m_track; - midiTime m_startPosition; - midiTime m_length; - actions m_action; + trackContentObject * m_tco; + trackView * m_trackView; + Actions m_action; bool m_autoResize; Sint16 m_initialMouseX; - bool m_muted; - textFloat * m_hint; midiTime m_oldTime;// used for undo/redo while mouse-button is pressed @@ -160,39 +216,30 @@ private: + class trackContentWidget : public QWidget, public journallingObject { Q_OBJECT public: - trackContentWidget( trackWidget * _parent ); + trackContentWidget( trackView * _parent ); virtual ~trackContentWidget(); - trackContentObject * FASTCALL getTCO( int _tco_num ); - int numOfTCOs( void ); - trackContentObject * FASTCALL addTCO( trackContentObject * _tco ); - void FASTCALL removeTCO( int _tco_num, bool _also_delete = TRUE ); - void FASTCALL removeTCO( trackContentObject * _tco, - bool _also_delete = TRUE ); - void removeAllTCOs( void ); - void FASTCALL swapPositionOfTCOs( int _tco_num1, int _tco_num2 ); - - inline Uint16 pixelsPerTact( void ) const + void addTCOView( trackContentObjectView * _tcov ); + void removeTCOView( trackContentObjectView * _tcov ); + void removeTCOView( int _tco_num ) { - return( m_pixelsPerTact ); + if( _tco_num >= 0 && _tco_num < m_tcoViews.size() ) + { + removeTCOView( m_tcoViews[_tco_num] ); + } } - inline void setPixelsPerTact( Uint16 _ppt ) - { - m_pixelsPerTact = _ppt; - } - - tact length( void ) const; + midiTime endPosition( const midiTime & _pos_start ); public slots: - void insertTact( const midiTime & _pos ); - void removeTact( const midiTime & _pos ); void update( void ); + void changePosition( const midiTime & _new_pos = -1 ); protected: @@ -212,19 +259,21 @@ protected: private: - enum actions + enum Actions { - ADD_TCO, REMOVE_TCO + AddTrackContentObject, + RemoveTrackContentObject } ; track * getTrack( void ); midiTime getPosition( int _mouse_x ); - typedef QVector tcoVector; + trackView * m_trackView; - tcoVector m_trackContentObjects; - trackWidget * m_trackWidget; - Uint16 m_pixelsPerTact; + typedef QVector tcoViewVector; + tcoViewVector m_tcoViews; + + int m_pixelsPerTact; } ; @@ -236,7 +285,7 @@ class trackOperationsWidget : public QWidget { Q_OBJECT public: - trackOperationsWidget( trackWidget * _parent ); + trackOperationsWidget( trackView * _parent ); ~trackOperationsWidget(); bool muted( void ) const; @@ -267,7 +316,7 @@ private: static QPixmap * s_muteOnDisabled; static QPixmap * s_muteOnEnabled; - trackWidget * m_trackWidget; + trackView * m_trackView; QPushButton * m_trackOps; pixmapButton * m_muteBtn; @@ -283,14 +332,137 @@ private: +// base-class for all tracks +class track : public model, public journallingObject +{ + Q_OBJECT + mapPropertyFromModel(bool,muted,setMuted,m_mutedModel); +public: + enum TrackTypes + { + InstrumentTrack, + BBTrack, + SampleTrack, + EventTrack, + VideoTrack, + AutomationTrack, + NumTrackTypes + } ; -// actual widget shown in trackContainer -class trackWidget : public QWidget, public journallingObject + track( TrackTypes _type, trackContainer * _tc ); + virtual ~track(); + + static track * create( TrackTypes _tt, trackContainer * _tc ); + static track * create( const QDomElement & _this, + trackContainer * _tc ); + void clone( void ); + + + // pure virtual functions + TrackTypes type( void ) const + { + return( m_type ); + } + + virtual bool play( const midiTime & _start, const fpp_t _frames, + const f_cnt_t _frame_base, + Sint16 _tco_num = -1 ) = 0; + + + virtual trackView * createView( trackContainerView * _view ) = 0; + virtual trackContentObject * createTCO( const midiTime & _pos ) = 0; + + virtual void saveTrackSpecificSettings( QDomDocument & _doc, + QDomElement & _parent ) = 0; + virtual void loadTrackSpecificSettings( const QDomElement & _this ) = 0; + + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); + virtual void loadSettings( const QDomElement & _this ); + + + // -- for usage by trackContentObject only --------------- + trackContentObject * addTCO( trackContentObject * _tco ); + void removeTCO( trackContentObject * _tco ); + // ------------------------------------------------------- + + int numOfTCOs( void ); + trackContentObject * getTCO( int _tco_num ); + int getTCONum( trackContentObject * _tco ); + + void getTCOsInRange( QList & _tco_v, + const midiTime & _start, + const midiTime & _end ); + void swapPositionOfTCOs( int _tco_num1, int _tco_num2 ); + + void insertTact( const midiTime & _pos ); + void removeTact( const midiTime & _pos ); + + tact length( void ) const; + + inline trackContainer * getTrackContainer( void ) const + { + return( m_trackContainer ); + } + + void addAutomationPattern( automationPattern * _pattern ); + void removeAutomationPattern( automationPattern * _pattern ); + + // name-stuff + virtual const QString & name( void ) const + { + return( m_name ); + } + + inline const QPixmap * pixmap( void ) + { + return( m_pixmap ); + } + + using model::dataChanged; + + +public slots: + virtual void setName( const QString & _new_name ) + { + m_name = _new_name; + } + + +protected: + void sendMidiTime( const midiTime & _time ); + + +private: + trackContainer * m_trackContainer; + TrackTypes m_type; + QString m_name; + QPixmap * m_pixmap; + boolModel m_mutedModel; + + typedef QVector tcoVector; + tcoVector m_trackContentObjects; + + QList m_automationPatterns; + + + friend class trackView; + + +signals: + void trackContentObjectAdded( trackContentObject * ); + +} ; + + + + +class trackView : public QWidget, public modelView, public journallingObject { Q_OBJECT public: - trackWidget( track * _track, QWidget * _parent ); - virtual ~trackWidget(); + trackView( track * _track, trackContainerView * _tcv ); + virtual ~trackView(); inline const track * getTrack( void ) const { @@ -302,56 +474,46 @@ public: return( m_track ); } - inline const trackOperationsWidget & getTrackOperationsWidget( void ) - const + inline trackContainerView * getTrackContainerView( void ) { - return( m_trackOperationsWidget ); + return( m_trackContainerView ); } - inline const trackSettingsWidget & getTrackSettingsWidget( void ) const + inline trackOperationsWidget * getTrackOperationsWidget( void ) { - return( m_trackSettingsWidget ); + return( &m_trackOperationsWidget ); } - inline const trackContentWidget & getTrackContentWidget( void ) const + inline trackSettingsWidget * getTrackSettingsWidget( void ) { - return( m_trackContentWidget ); + return( &m_trackSettingsWidget ); } - inline trackOperationsWidget & getTrackOperationsWidget( void ) + inline trackContentWidget * getTrackContentWidget( void ) { - return( m_trackOperationsWidget ); - } - - inline trackSettingsWidget & getTrackSettingsWidget( void ) - { - return( m_trackSettingsWidget ); - } - - inline trackContentWidget & getTrackContentWidget( void ) - { - return( m_trackContentWidget ); + return( &m_trackContentWidget ); } bool isMovingTrack( void ) const { - return( m_action == MOVE_TRACK ); + return( m_action == MoveTrack ); } - + virtual void update( void ); public slots: - void changePosition( const midiTime & _new_pos = -1 ); + virtual bool close( void ); protected: + virtual void modelChanged( void ); virtual void undoStep( journalEntry & _je ); virtual void redoStep( journalEntry & _je ); virtual QString nodeName( void ) const { - return( "trackwidget" ); + return( "trackview" ); } @@ -363,153 +525,30 @@ protected: virtual void paintEvent( QPaintEvent * _pe ); virtual void resizeEvent( QResizeEvent * _re ); - midiTime FASTCALL endPosition( const midiTime & _pos_start ); - private: - enum actions + enum Actions { - NONE, MOVE_TRACK, RESIZE_TRACK + NoAction, + MoveTrack, + ResizeTrack } ; + track * m_track; + trackContainerView * m_trackContainerView; trackOperationsWidget m_trackOperationsWidget; trackSettingsWidget m_trackSettingsWidget; trackContentWidget m_trackContentWidget; - actions m_action; + Actions m_action; + + +private slots: + void createTCOView( trackContentObject * _tco ); } ; - -// base-class for all tracks -class track : public journallingObject -{ -public: - enum trackTypes - { - INSTRUMENT_TRACK, - BB_TRACK, - SAMPLE_TRACK, - EVENT_TRACK, - VIDEO_TRACK, - AUTOMATION_TRACK, - TOTAL_TRACK_TYPES - } ; - - track( trackContainer * _tc, bool _create_widget = TRUE ); - virtual ~track(); - - static track * FASTCALL create( trackTypes _tt, trackContainer * _tc ); - static void FASTCALL create( const QDomElement & _this, - trackContainer * _tc ); - void FASTCALL clone( void ); - - tact length( void ) const; - - inline bool muted( void ) const - { - return( m_trackWidget->getTrackOperationsWidget().muted() ); - } - - inline void setMuted( bool _muted ) - { - m_trackWidget->getTrackOperationsWidget().setMuted( _muted ); - } - - - // pure virtual functions - virtual trackTypes type( void ) const = 0; - - virtual bool FASTCALL play( const midiTime & _start, - const fpp_t _frames, - const f_cnt_t _frame_base, - Sint16 _tco_num = -1 ) = 0; - - - virtual trackContentObject * FASTCALL createTCO( - const midiTime & _pos ) = 0; - - virtual void FASTCALL saveTrackSpecificSettings( QDomDocument & _doc, - QDomElement & _parent ) = 0; - virtual void FASTCALL loadTrackSpecificSettings( - const QDomElement & _this ) = 0; - - - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _this ); - virtual void FASTCALL loadSettings( const QDomElement & _this ); - - - trackContentObject * FASTCALL addTCO( trackContentObject * _tco ); - void FASTCALL removeTCO( int _tco_num ); - int numOfTCOs( void ); - trackContentObject * FASTCALL getTCO( int _tco_num ); - int FASTCALL getTCONum( trackContentObject * _tco ); - void FASTCALL getTCOsInRange( QList & _tco_v, - const midiTime & _start, - const midiTime & _end ); - void FASTCALL swapPositionOfTCOs( int _tco_num1, int _tco_num2 ); - - inline trackWidget * getTrackWidget( void ) - { - return( m_trackWidget ); - } - - inline trackContainer * getTrackContainer( void ) const - { - return( m_trackContainer ); - } - - inline const trackSettingsWidget * getTrackSettingsWidget( void ) const - { - return( &m_trackWidget->getTrackSettingsWidget() ); - } - - inline const trackContentWidget * getTrackContentWidget( void ) const - { - return( &m_trackWidget->getTrackContentWidget() ); - } - - inline trackSettingsWidget * getTrackSettingsWidget( void ) - { - return( &m_trackWidget->getTrackSettingsWidget() ); - } - - inline trackContentWidget * getTrackContentWidget( void ) - { - return( &m_trackWidget->getTrackContentWidget() ); - } - - void addAutomationPattern( automationPattern * _pattern ); - void removeAutomationPattern( automationPattern * _pattern ); - - // name-stuff - inline virtual const QString & name( void ) const - { - return( m_name ); - } - inline virtual void setName( const QString & _new_name ) - { - m_name = _new_name; - } - - -protected: - void sendMidiTime( const midiTime & _time ); - QString m_name; - - -private: - trackContainer * m_trackContainer; - trackWidget * m_trackWidget; - QList m_automation_patterns; - -} ; - - - - #endif diff --git a/include/track_container.h b/include/track_container.h index b02a877918..e46b78cba8 100644 --- a/include/track_container.h +++ b/include/track_container.h @@ -2,7 +2,7 @@ * track_container.h - base-class for all track-containers like Song-Editor, * BB-Editor... * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -36,65 +36,98 @@ #include "journalling_object.h" +class trackContainerView; class QVBoxLayout; - -class trackContainer : public QWidget, public journallingObject +class trackContainer : public model, public journallingObject { Q_OBJECT public: trackContainer( void ); virtual ~trackContainer(); + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + + virtual void loadSettings( const QDomElement & _this ); + + + virtual automationPattern * tempoAutomationPattern( void ) + { + return( NULL ); + } + + int countTracks( track::TrackTypes _tt = track::NumTrackTypes ) const; + + void setMutedOfAllTracks( bool _muted ); + + + virtual void updateAfterTrackAdd( void ); + void addTrack( track * _track ); + void removeTrack( track * _track ); + + void clearAllTracks( void ); + + const QList & tracks( void ) const + { + return( m_tracks ); + } + + static const QString classNodeName( void ) + { + return( "trackcontainer" ); + } + + + //const QList tracks( void ) const; + + +signals: + void trackAdded( track * _track ); + + +private: + QList m_tracks; + + + friend class trackContainerView; + + +} ; + + + +class trackContainerView : public QWidget, public modelView, + public journallingObject +{ + Q_OBJECT +public: + trackContainerView( trackContainer * _tc ); + virtual ~trackContainerView(); + QWidget * contentWidget( void ) { return( m_scrollArea ); } - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); - - virtual void FASTCALL loadSettings( const QDomElement & _this ); - - - inline float pixelsPerTact( void ) const - { - return( m_ppt ); - } - inline const midiTime & currentPosition( void ) const { return( m_currentPosition ); } - virtual automationPattern * tempoAutomationPattern( void ) - { - return( NULL ); - } - virtual bool fixedTCOs( void ) const { return( FALSE ); } - Uint16 FASTCALL countTracks( track::trackTypes _tt = - track::TOTAL_TRACK_TYPES ) const; + inline float pixelsPerTact( void ) const + { + return( m_ppt ); + } - void FASTCALL setMutedOfAllTracks( bool _muted ); + void setPixelsPerTact( int _ppt ); - - virtual void updateAfterTrackAdd( void ); - void FASTCALL setPixelsPerTact( Uint16 _ppt ); - void FASTCALL addTrack( track * _track ); - void FASTCALL removeTrack( track * _track ); - void FASTCALL moveTrackUp( track * _track ); - void FASTCALL moveTrackDown( track * _track ); - - void FASTCALL realignTracks( void ); - void clearAllTracks( void ); - - const trackWidget * trackWidgetAt( const int _y ) const; + const trackView * trackViewAt( const int _y ) const; virtual bool allowRubberband( void ) const; @@ -110,73 +143,101 @@ public: return( m_rubberBand->selectedObjects() ); } return( QVector() ); -/* QVector foo; - return( foo );*/ } - QList tracks( void ); - static const QString classNodeName( void ) + trackContainer * model( void ) { - return( "trackcontainer" ); + return( m_tc ); + } + + const trackContainer * model( void ) const + { + return( m_tc ); + } + + void moveTrackViewUp( trackView * _tv ); + void moveTrackViewDown( trackView * _tv ); + + // -- for usage by trackView only --------------- + trackView * addTrackView( trackView * _tv ); + void removeTrackView( trackView * _tv ); + // ------------------------------------------------------- + + void clearAllTracks( void ); + + virtual QString nodeName( void ) const + { + return( "trackcontainerview" ); } -signals: - void positionChanged( const midiTime & _pos ); +public slots: + void realignTracks( void ); + void createTrackView( track * _t ); protected: - static const Uint16 DEFAULT_PIXELS_PER_TACT = 16; + static const int DEFAULT_PIXELS_PER_TACT = 16; - virtual void undoStep( journalEntry & _je ); - virtual void redoStep( journalEntry & _je ); + const QList & trackViews( void ) const + { + return( m_trackViews ); + } virtual void dragEnterEvent( QDragEnterEvent * _dee ); virtual void dropEvent( QDropEvent * _de ); - virtual void mousePressEvent( QMouseEvent * _me ); virtual void mouseMoveEvent( QMouseEvent * _me ); virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void resizeEvent( QResizeEvent * ); - const QList tracks( void ) const; + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); midiTime m_currentPosition; private: - enum actions + enum Actions { - ADD_TRACK, REMOVE_TRACK + AddTrack, + RemoveTrack } ; class scrollArea : public QScrollArea { public: - scrollArea( trackContainer * _parent ); + scrollArea( trackContainerView * _parent ); virtual ~scrollArea(); protected: virtual void wheelEvent( QWheelEvent * _we ); private: - trackContainer * m_trackContainer; + trackContainerView * m_trackContainerView; } ; + trackContainer * m_tc; + typedef QList trackViewList; + trackViewList m_trackViews; scrollArea * m_scrollArea; QVBoxLayout * m_scrollLayout; - QList m_tracks; float m_ppt; rubberBand * m_rubberBand; QPoint m_origin; + +signals: + void positionChanged( const midiTime & _pos ); + + } ; + #endif diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index 25fc3fc397..4574cd99f8 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -33,7 +33,7 @@ #include "audio_file_processor.h" #include "automatable_model_templates.h" #include "engine.h" -#include "song_editor.h" +#include "song.h" #include "instrument_track.h" #include "note_play_handle.h" #include "interpolation.h" @@ -447,7 +447,7 @@ void audioFileProcessorView::dragEnterEvent( QDragEnterEvent * _dee ) QString txt = _dee->mimeData()->data( stringPairDrag::mimeType() ); if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg( - track::SAMPLE_TRACK ) ) + track::SampleTrack ) ) { _dee->acceptProposedAction(); } @@ -479,7 +479,7 @@ void audioFileProcessorView::dropEvent( QDropEvent * _de ) _de->accept(); return; } - else if( type == QString( "tco_%1" ).arg( track::SAMPLE_TRACK ) ) + else if( type == QString( "tco_%1" ).arg( track::SampleTrack ) ) { multimediaProject mmp( value, FALSE ); castModel()->setAudioFile( mmp.content(). @@ -572,7 +572,7 @@ void audioFileProcessorView::openAudioFile( void ) if( af != "" ) { castModel()->setAudioFile( af ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } diff --git a/plugins/ladspa_effect/ladspa_controls.cpp b/plugins/ladspa_effect/ladspa_controls.cpp index e956e19da6..746b8d9e62 100644 --- a/plugins/ladspa_effect/ladspa_controls.cpp +++ b/plugins/ladspa_effect/ladspa_controls.cpp @@ -34,8 +34,7 @@ ladspaControls::ladspaControls( ladspaEffect * _eff, m_processors( _eff->getProcessorCount() ), m_track( _track ), m_noLink( FALSE ), - m_stereoLinkModel( TRUE, FALSE, TRUE, boolModel::defaultRelStep(), - this ) + m_stereoLinkModel( TRUE, this ) { multi_proc_t controls = m_effect->getPortControls(); m_controlCount = controls.count(); diff --git a/plugins/stk/Makefile.am b/plugins/stk/Makefile.am index 4eb93be39f..2a02d95187 100644 --- a/plugins/stk/Makefile.am +++ b/plugins/stk/Makefile.am @@ -1,2 +1 @@ -SUBDIRS = mallets -# voices \ No newline at end of file +SUBDIRS = mallets voices diff --git a/src/core/arp_and_chords_tab_widget.cpp b/src/core/arp_and_chords_tab_widget.cpp deleted file mode 100644 index 859451fad3..0000000000 --- a/src/core/arp_and_chords_tab_widget.cpp +++ /dev/null @@ -1,667 +0,0 @@ -#ifndef SINGLE_SOURCE_COMPILE - -/* - * arp_and_chords_tab_widget.cpp - widget for use in arp/chord-tab of - * instrument-track-window - * - * Copyright (c) 2004-2008 Tobias Doerffel - * - * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - */ - - -#include -#include - - -#include "arp_and_chords_tab_widget.h" -#include "combobox.h" -#include "embed.h" -#include "engine.h" -#include "group_box.h" -#include "gui_templates.h" -#include "instrument_track.h" -#include "knob.h" -#include "led_checkbox.h" -#include "note_play_handle.h" -#include "song_editor.h" -#include "pixmap_button.h" -#include "preset_preview_play_handle.h" -#include "tempo_sync_knob.h" -#include "tooltip.h" - - - -arpAndChordsTabWidget::chord arpAndChordsTabWidget::s_chords[] = -{ - { arpAndChordsTabWidget::tr( "octave" ), { 0, -1 } }, - { arpAndChordsTabWidget::tr( "Major" ), { 0, 4, 7, -1 } }, - { arpAndChordsTabWidget::tr( "Majb5" ), { 0, 4, 6, -1 } }, - { arpAndChordsTabWidget::tr( "minor" ), { 0, 3, 7, -1 } }, - { arpAndChordsTabWidget::tr( "minb5" ), { 0, 3, 6, -1 } }, - { arpAndChordsTabWidget::tr( "sus2" ), { 0, 2, 7, -1 } }, - { arpAndChordsTabWidget::tr( "sus4" ), { 0, 5, 7, -1 } }, - { arpAndChordsTabWidget::tr( "aug" ), { 0, 4, 8, -1 } }, - { arpAndChordsTabWidget::tr( "augsus4" ), { 0, 5, 8, -1 } }, - { arpAndChordsTabWidget::tr( "tri" ), { 0, 3, 6, 9, -1 } }, - - { arpAndChordsTabWidget::tr( "6" ), { 0, 4, 7, 9, -1 } }, - { arpAndChordsTabWidget::tr( "6sus4" ), { 0, 5, 7, 9, -1 } }, - { arpAndChordsTabWidget::tr( "6add9" ), { 0, 4, 7, 12, -1 } }, - { arpAndChordsTabWidget::tr( "m6" ), { 0, 3, 7, 9, -1 } }, - { arpAndChordsTabWidget::tr( "m6add9" ), { 0, 3, 7, 9, 14, -1 } }, - - { arpAndChordsTabWidget::tr( "7" ), { 0, 4, 7, 10, -1 } }, - { arpAndChordsTabWidget::tr( "7sus4" ), { 0, 5, 7, 10, -1 } }, - { arpAndChordsTabWidget::tr( "7#5" ), { 0, 4, 8, 10, -1 } }, - { arpAndChordsTabWidget::tr( "7b5" ), { 0, 4, 6, 10, -1 } }, - { arpAndChordsTabWidget::tr( "7#9" ), { 0, 4, 7, 10, 13, 18, -1 } }, - { arpAndChordsTabWidget::tr( "7b9" ), { 0, 4, 7, 10, 13, 16, -1 } }, - { arpAndChordsTabWidget::tr( "7#5#9" ), { 0, 4, 8, 12, 14, 19, -1 } }, - { arpAndChordsTabWidget::tr( "7#5b9" ), { 0, 4, 8, 12, 14, 17, -1 } }, - { arpAndChordsTabWidget::tr( "7b5b9" ), { 0, 4, 6, 10, 12, 15, -1 } }, - { arpAndChordsTabWidget::tr( "7add11" ), { 0, 4, 7, 10, 17, -1 } }, - { arpAndChordsTabWidget::tr( "7add13" ), { 0, 4, 7, 10, 21, -1 } }, - { arpAndChordsTabWidget::tr( "7#11" ), { 0, 4, 7, 10, 18, -1 } }, - { arpAndChordsTabWidget::tr( "Maj7" ), { 0, 4, 7, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Maj7b5" ), { 0, 4, 6, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Maj7#5" ), { 0, 4, 8, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Maj7#11" ), { 0, 4, 7, 11, 18, -1 } }, - { arpAndChordsTabWidget::tr( "Maj7add13" ), { 0, 4, 7, 11, 21, -1 } }, - { arpAndChordsTabWidget::tr( "m7" ), { 0, 3, 7, 10, -1 } }, - { arpAndChordsTabWidget::tr( "m7b5" ), { 0, 3, 6, 10, -1 } }, - { arpAndChordsTabWidget::tr( "m7b9" ), { 0, 3, 7, 10, 13, -1 } }, - { arpAndChordsTabWidget::tr( "m7add11" ), { 0, 3, 7, 10, 17, -1 } }, - { arpAndChordsTabWidget::tr( "m7add13" ), { 0, 3, 7, 10, 21, -1 } }, - { arpAndChordsTabWidget::tr( "m-Maj7" ), { 0, 3, 7, 11, -1 } }, - { arpAndChordsTabWidget::tr( "m-Maj7add11" ), { 0, 3, 7, 11, 17, -1 } }, - { arpAndChordsTabWidget::tr( "m-Maj7add13" ), { 0, 3, 7, 11, 21, -1 } }, - - { arpAndChordsTabWidget::tr( "9" ), { 0, 4, 7, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "9sus4" ), { 0, 5, 7, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "add9" ), { 0, 4, 7, 14, -1 } }, - { arpAndChordsTabWidget::tr( "9#5" ), { 0, 4, 8, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "9b5" ), { 0, 4, 6, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "9#11" ), { 0, 4, 7, 10, 14, 18, -1 } }, - { arpAndChordsTabWidget::tr( "9b13" ), { 0, 4, 7, 10, 14, 20, -1 } }, - { arpAndChordsTabWidget::tr( "Maj9" ), { 0, 4, 7, 11, 14, -1 } }, - { arpAndChordsTabWidget::tr( "Maj9sus4" ), { 0, 5, 7, 11, 15, -1 } }, - { arpAndChordsTabWidget::tr( "Maj9#5" ), { 0, 4, 8, 11, 14, -1 } }, - { arpAndChordsTabWidget::tr( "Maj9#11" ), { 0, 4, 7, 11, 14, 18, -1 } }, - { arpAndChordsTabWidget::tr( "m9" ), { 0, 3, 7, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "madd9" ), { 0, 3, 7, 14, -1 } }, - { arpAndChordsTabWidget::tr( "m9b5" ), { 0, 3, 6, 10, 14, -1 } }, - { arpAndChordsTabWidget::tr( "m9-Maj7" ), { 0, 3, 7, 11, 14, -1 } }, - - { arpAndChordsTabWidget::tr( "11" ), { 0, 4, 7, 10, 14, 17, -1 } }, - { arpAndChordsTabWidget::tr( "11b9" ), { 0, 4, 7, 10, 13, 17, -1 } }, - { arpAndChordsTabWidget::tr( "Maj11" ), { 0, 4, 7, 11, 14, 17, -1 } }, - { arpAndChordsTabWidget::tr( "m11" ), { 0, 3, 7, 10, 14, 17, -1 } }, - { arpAndChordsTabWidget::tr( "m-Maj11" ), { 0, 3, 7, 11, 14, 17, -1 } }, - - { arpAndChordsTabWidget::tr( "13" ), { 0, 4, 7, 10, 14, 21, -1 } }, - { arpAndChordsTabWidget::tr( "13#9" ), { 0, 4, 7, 10, 15, 21, -1 } }, - { arpAndChordsTabWidget::tr( "13b9" ), { 0, 4, 7, 10, 13, 21, -1 } }, - { arpAndChordsTabWidget::tr( "13b5b9" ), { 0, 4, 6, 10, 13, 21, -1 } }, - { arpAndChordsTabWidget::tr( "Maj13" ), { 0, 4, 7, 11, 14, 21, -1 } }, - { arpAndChordsTabWidget::tr( "m13" ), { 0, 3, 7, 10, 14, 21, -1 } }, - { arpAndChordsTabWidget::tr( "m-Maj13" ), { 0, 3, 7, 11, 14, 21, -1 } }, - - { arpAndChordsTabWidget::tr( "Major" ), { 0, 2, 4, 5, 7, 9, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Harmonic minor" ), { 0, 2, 3, 5, 7, 8, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Melodic minor" ), { 0, 2, 3, 5, 7, 9, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Whole tone" ), { 0, 2, 4, 6, 8, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Diminished" ), { 0, 2, 3, 5, 6, 8, 9, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Major pentatonic" ), { 0, 2, 4, 7, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Minor pentatonic" ), { 0, 3, 5, 7, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Jap in sen" ), { 0, 1, 5, 7, 10, -1 } }, - { arpAndChordsTabWidget::tr( "Major bebop" ), { 0, 2, 4, 5, 7, 8, 9, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Dominant bebop" ), { 0, 2, 4, 5, 7, 9, - 10, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Blues" ), { 0, 3, 5, 6, 7, 10, -1 } }, - { arpAndChordsTabWidget::tr( "Arabic" ), { 0, 1, 4, 5, 7, 8, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Enigmatic" ), { 0, 1, 4, 6, 8, 10, 11, - -1 } }, - { arpAndChordsTabWidget::tr( "Neopolitan" ), { 0, 1, 3, 5, 7, 9, 11, - -1 } }, - { arpAndChordsTabWidget::tr( "Neopolitan minor" ), { 0, 1, 3, 5, 7, 9, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Hungarian minor" ), { 0, 2, 3, 6, 7, 9, - 11, -1 } }, - { arpAndChordsTabWidget::tr( "Dorian" ), { 0, 2, 3, 5, 7, 9, 10, -1 } }, - { arpAndChordsTabWidget::tr( "Phrygolydian" ), { 0, 1, 3, 5, 7, 8, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Lydian" ), { 0, 2, 4, 6, 7, 9, 11, -1 } }, - { arpAndChordsTabWidget::tr( "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, - -1 } }, - { arpAndChordsTabWidget::tr( "Locrian" ), { 0, 1, 3, 5, 6, 8, 10, - -1 } }, - - { "", { -1, -1 } } - -} ; - - -const int CHORDS_GROUPBOX_X = 4; -const int CHORDS_GROUPBOX_Y = 5; -const int CHORDS_GROUPBOX_WIDTH = 238; -const int CHORDS_GROUPBOX_HEIGHT = 65; -const int ARP_GROUPBOX_X = CHORDS_GROUPBOX_X; -const int ARP_GROUPBOX_Y = 10 + CHORDS_GROUPBOX_Y + CHORDS_GROUPBOX_HEIGHT; -const int ARP_GROUPBOX_WIDTH = CHORDS_GROUPBOX_WIDTH; -const int ARP_GROUPBOX_HEIGHT = 240 - ARP_GROUPBOX_Y; - - - -arpAndChordsTabWidget::arpAndChordsTabWidget( - instrumentTrack * _instrument_track ) : - QWidget( _instrument_track->tabWidgetParent() ), - m_chordsEnabledModel( new boolModel( FALSE ) ), - m_chordsModel( new comboBoxModel( /* this */ ) ), - m_chordRangeModel( new floatModel( 1.0f, 1.0f, 9.0f, 1.0f - /* this */ ) ), - m_arpEnabledModel( new boolModel( FALSE ) ), - m_arpModel( new comboBoxModel( /* this */ ) ), - m_arpRangeModel( new floatModel( 1.0f, 1.0f, 9.0f, 1.0f - /* this */ ) ), - m_arpTimeModel( new floatModel( 100.0f, 25.0f, 2000.0f, 1.0f - /* this */ ) ), - m_arpGateModel( new floatModel( 100.0f, 1.0f, 200.0f, 1.0f - /* this */ ) ), - m_arpDirectionModel( new intModel( /* this */ ) ), - m_arpModeModel( new comboBoxModel( /* this */ ) ) -{ - m_chordsEnabledModel->setTrack( _instrument_track ); - m_chordsGroupBox = new groupBox( tr( "CHORDS" ), this ); - m_chordsGroupBox->setGeometry( CHORDS_GROUPBOX_X, CHORDS_GROUPBOX_Y, - CHORDS_GROUPBOX_WIDTH, - CHORDS_GROUPBOX_HEIGHT ); - m_chordsGroupBox->setModel( m_chordsEnabledModel ); - - - m_chordsModel->setTrack( _instrument_track ); - m_chordsComboBox = new comboBox( m_chordsGroupBox, tr( "Chord type" ) ); - m_chordsComboBox->setGeometry( 10, 25, 140, 22 ); - - for( int i = 0; s_chords[i].interval[0] != -1; ++i ) - { - m_chordsModel->addItem( tr( s_chords[i].name.toAscii(). - constData() ) ); - } - m_chordsComboBox->setModel( m_chordsModel ); - - - m_chordRangeModel->setTrack( _instrument_track ); - m_chordRangeModel->setInitValue( 1.0f ); - m_chordRangeKnob = new knob( knobBright_26, m_chordsGroupBox, - tr( "Chord range" ) ); - m_chordRangeKnob->setModel( m_chordRangeModel ); - m_chordRangeKnob->setLabel( tr( "RANGE" ) ); - m_chordRangeKnob->move( 164, 24 ); - m_chordRangeKnob->setHintText( tr( "Chord range:" ) + " ", " " + - tr( "octave(s)" ) ); - m_chordRangeKnob->setWhatsThis( - tr( "Use this knob for setting the chord range in octaves. " - "The selected chord will be played within specified " - "amount of octaves." ) ); - - - - m_arpEnabledModel->setTrack( _instrument_track ); - m_arpGroupBox = new groupBox( tr( "ARPEGGIO" ), this ); - m_arpGroupBox->setModel( m_arpEnabledModel ); - m_arpGroupBox->setGeometry( ARP_GROUPBOX_X, ARP_GROUPBOX_Y, - ARP_GROUPBOX_WIDTH, - ARP_GROUPBOX_HEIGHT ); - - m_arpGroupBox->setWhatsThis( - tr( "An arpeggio is a type of playing (especially plucked) " - "instruments, which makes the music much livelier. " - "The strings of such instruments (e.g. harps) are " - "plucked like chords, the only difference is, that " - "this is done in a sequential order, so the notes are " - "not played at the same time. Typical arpeggios are " - "major or minor triads. But there're a lot of other " - "possible chords, you can select." ) ); - - - m_arpModel->setTrack( _instrument_track ); - m_arpComboBox = new comboBox( m_arpGroupBox, tr( "Arpeggio type" ) ); - m_arpComboBox->setGeometry( 10, 25, 140, 22 ); - - for( int i = 0; s_chords[i].interval[0] != -1; ++i ) - { - m_arpModel->addItem( tr( s_chords[i].name.toAscii(). - constData() ) ); - } - m_arpComboBox->setModel( m_arpModel ); - - - m_arpRangeModel->setTrack( _instrument_track ); - m_arpRangeModel->setInitValue( 1.0f ); - m_arpRangeKnob = new knob( knobBright_26, m_arpGroupBox, - tr( "Arpeggio range" ) ); - m_arpRangeKnob->setModel( m_arpRangeModel ); - m_arpRangeKnob->setLabel( tr( "RANGE" ) ); - m_arpRangeKnob->move( 164, 24 ); - m_arpRangeKnob->setHintText( tr( "Arpeggio range:" ) + " ", " " + - tr( "octave(s)" ) ); - m_arpRangeKnob->setWhatsThis( - tr( "Use this knob for setting the arpeggio range in octaves. " - "The selected arpeggio will be played within specified " - "amount of octaves." ) ); - - - m_arpTimeModel->setTrack( _instrument_track ); - m_arpTimeModel->setInitValue( 100.0f ); - m_arpTimeKnob = new tempoSyncKnob( knobBright_26, m_arpGroupBox, - tr( "Arpeggio time" ) ); - m_arpTimeKnob->setModel( m_arpTimeModel ); - m_arpTimeKnob->setLabel( tr( "TIME" ) ); - m_arpTimeKnob->move( 164, 70 ); - m_arpTimeKnob->setHintText( tr( "Arpeggio time:" ) + " ", " " + - tr( "ms" ) ); - m_arpTimeKnob->setWhatsThis( - tr( "Use this knob for setting the arpeggio time in " - "milliseconds. The arpeggio time specifies how long " - "each arpeggio-tone should be played." ) ); - - - m_arpGateModel->setTrack( _instrument_track ); - m_arpGateModel->setInitValue( 100.0f ); - m_arpGateKnob = new knob( knobBright_26, m_arpGroupBox, - tr( "Arpeggio gate" ) ); - m_arpGateKnob->setModel( m_arpGateModel ); - m_arpGateKnob->setLabel( tr( "GATE" ) ); - m_arpGateKnob->move( 204, 70 ); - m_arpGateKnob->setHintText( tr( "Arpeggio gate:" ) + " ", tr( "%" ) ); - m_arpGateKnob->setWhatsThis( - tr( "Use this knob for setting the arpeggio gate. The " - "arpeggio gate specifies the percent of a whole " - "arpeggio-tone that should be played. With this you " - "can make cool staccato-arpeggios." ) ); - - m_arpDirectionLbl = new QLabel( tr( "Direction:" ), m_arpGroupBox ); - m_arpDirectionLbl->setGeometry( 10, 60, 64, 10 ); - m_arpDirectionLbl->setFont( pointSize<7>( m_arpDirectionLbl->font() ) ); - - - - pixmapButton * arp_up_btn = new pixmapButton( m_arpGroupBox, NULL ); - arp_up_btn->move( 10, 74 ); - arp_up_btn->setActiveGraphic( embed::getIconPixmap( "arp_up_on" ) ); - arp_up_btn->setInactiveGraphic( embed::getIconPixmap( "arp_up_off" ) ); - toolTip::add( arp_up_btn, tr( "arpeggio direction = up" ) ); - - - pixmapButton * arp_down_btn = new pixmapButton( m_arpGroupBox, NULL ); - arp_down_btn->move( 30, 74 ); - arp_down_btn->setActiveGraphic( embed::getIconPixmap( "arp_down_on" ) ); - arp_down_btn->setInactiveGraphic( embed::getIconPixmap( - "arp_down_off" ) ); - toolTip::add( arp_down_btn, tr( "arpeggio direction = down" ) ); - - - pixmapButton * arp_up_and_down_btn = new pixmapButton( m_arpGroupBox, - NULL ); - arp_up_and_down_btn->move( 50, 74 ); - arp_up_and_down_btn->setActiveGraphic( embed::getIconPixmap( - "arp_up_and_down_on" ) ); - arp_up_and_down_btn->setInactiveGraphic( embed::getIconPixmap( - "arp_up_and_down_off" ) ); - toolTip::add( arp_up_and_down_btn, - tr( "arpeggio direction = up and down" ) ); - - - pixmapButton * arp_random_btn = new pixmapButton( m_arpGroupBox, NULL ); - arp_random_btn->move( 70, 74 ); - arp_random_btn->setActiveGraphic( embed::getIconPixmap( - "arp_random_on" ) ); - arp_random_btn->setInactiveGraphic( embed::getIconPixmap( - "arp_random_off" ) ); - toolTip::add( arp_random_btn, tr( "arpeggio direction = random" ) ); - - m_arpDirectionBtnGrp = new automatableButtonGroup( this, - tr( "Arpeggio direction" ) ); - m_arpDirectionBtnGrp->setModel( m_arpDirectionModel ); - m_arpDirectionBtnGrp->addButton( arp_up_btn ); - m_arpDirectionBtnGrp->addButton( arp_down_btn ); - m_arpDirectionBtnGrp->addButton( arp_up_and_down_btn ); - m_arpDirectionBtnGrp->addButton( arp_random_btn ); - - m_arpDirectionModel->setTrack( _instrument_track ); - m_arpDirectionModel->setInitValue( UP ); - - - QLabel * mode_lbl = new QLabel( tr( "Mode:" ), m_arpGroupBox ); - mode_lbl->setGeometry( 10, 104, 64, 10 ); - mode_lbl->setFont( pointSize<7>( mode_lbl->font() ) ); - - m_arpModeComboBox = new comboBox( m_arpGroupBox, - tr( "Arpeggio mode" ) ); - m_arpModeComboBox->setGeometry( 10, 118, 128, 22 ); - - m_arpModeModel->setTrack( _instrument_track ); - m_arpModeModel->addItem( tr( "Free" ), new QPixmap( - embed::getIconPixmap( "arp_free" ) ) ); - m_arpModeModel->addItem( tr( "Sort" ), new QPixmap( - embed::getIconPixmap( "arp_sort" ) ) ); - m_arpModeModel->addItem( tr( "Sync" ), new QPixmap( - embed::getIconPixmap( "arp_sync" ) ) ); - m_arpModeComboBox->setModel( m_arpModeModel ); -} - - - - -arpAndChordsTabWidget::~arpAndChordsTabWidget() -{ -} - - - - -void arpAndChordsTabWidget::processNote( notePlayHandle * _n ) -{ - const int base_note_key = _n->key(); - // we add chord-subnotes to note if either note is a base-note and - // arpeggio is not used or note is part of an arpeggio - // at the same time we only add sub-notes if nothing of the note was - // played yet, because otherwise we would add chord-subnotes every - // time an audio-buffer is rendered... - if( ( ( _n->baseNote() && m_arpEnabledModel->value() == FALSE ) || - _n->arpNote() ) && - _n->totalFramesPlayed() == 0 && - m_chordsEnabledModel->value() == TRUE ) - { - // then insert sub-notes for chord - const int selected_chord = m_chordsComboBox->value(); - - for( int octave_cnt = 0; - octave_cnt < m_chordRangeKnob->value(); ++octave_cnt ) - { - const int sub_note_key_base = base_note_key + - octave_cnt * NOTES_PER_OCTAVE; - // if octave_cnt == 1 we're in the first octave and - // the base-note is already done, so we don't have to - // create it in the following loop, then we loop until - // there's a -1 in the interval-array - for( int i = ( octave_cnt == 0 ) ? 1 : 0; - s_chords[selected_chord].interval[i] != -1; - ++i ) - { - // add interval to sub-note-key - const int sub_note_key = sub_note_key_base + - (int) s_chords[ - selected_chord].interval[i]; - // maybe we're out of range -> let's get outta - // here! - if( sub_note_key > NOTES_PER_OCTAVE*OCTAVES ) - { - break; - } - // create copy of base-note - note note_copy( _n->length(), 0, - (tones)( sub_note_key % - NOTES_PER_OCTAVE ), - (octaves)( sub_note_key / - NOTES_PER_OCTAVE ), - _n->getVolume(), - _n->getPanning(), - _n->detuning() ); - // create sub-note-play-handle, only note is - // different - new notePlayHandle( _n->getInstrumentTrack(), - _n->offset(), - _n->frames(), note_copy, - _n ); - } - } - } - - - // now follows code for arpeggio - - if( _n->baseNote() == FALSE || - !m_arpEnabledModel->value() || - ( _n->released() && _n->releaseFramesDone() >= - _n->actualReleaseFramesToDo() ) ) - { - return; - } - - - const int selected_arp = m_arpComboBox->value(); - - constNotePlayHandleVector cnphv = notePlayHandle::nphsOfInstrumentTrack( - _n->getInstrumentTrack() ); - if( m_arpModeComboBox->value() != FREE && cnphv.size() == 0 ) - { - // maybe we're playing only a preset-preview-note? - cnphv = presetPreviewPlayHandle::nphsOfInstrumentTrack( - _n->getInstrumentTrack() ); - if( cnphv.size() == 0 ) - { - // still nothing found here, so lets return - //return; - cnphv.push_back( _n ); - } - } - - const int cur_chord_size = getChordSize( s_chords[selected_arp] ); - const int range = (int)( cur_chord_size * m_arpRangeKnob->value() ); - const int total_range = range * cnphv.size(); - - // number of frames that every note should be played - const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeKnob->value() / 1000.0f * - engine::getMixer()->sampleRate() ); - const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateKnob->value() * - arp_frames / 100.0f ); - - // used for calculating remaining frames for arp-note, we have to add - // arp_frames-1, otherwise the first arp-note will not be setup - // correctly... -> arp_frames frames silence at the start of every note! - int cur_frame = ( ( m_arpModeComboBox->value() != FREE ) ? - cnphv.first()->totalFramesPlayed() : - _n->totalFramesPlayed() ) + arp_frames - 1; - // used for loop - f_cnt_t frames_processed = 0; - - while( frames_processed < engine::getMixer()->framesPerPeriod() ) - { - const f_cnt_t remaining_frames_for_cur_arp = arp_frames - - ( cur_frame % arp_frames ); - // does current arp-note fill whole audio-buffer? - if( remaining_frames_for_cur_arp > - engine::getMixer()->framesPerPeriod() ) - { - // then we don't have to do something! - break; - } - - frames_processed += remaining_frames_for_cur_arp; - - // init with zero - int cur_arp_idx = 0; - - // in sorted mode: is it our turn or do we have to be quiet for - // now? - if( m_arpModeComboBox->value() == SORT && - ( ( cur_frame / arp_frames ) % total_range ) / - range != (f_cnt_t) _n->index() ) - { - // update counters - frames_processed += arp_frames; - cur_frame += arp_frames; - continue; - } - - const int dir = m_arpDirectionBtnGrp->value(); - // process according to arpeggio-direction... - if( dir == UP ) - { - cur_arp_idx = ( cur_frame / arp_frames ) % range; - } - else if( dir == DOWN ) - { - cur_arp_idx = range - ( cur_frame / arp_frames ) % - range - 1; - } - else if( dir == UP_AND_DOWN && range > 1 ) - { - // imagine, we had to play the arp once up and then - // once down -> makes 2 * range possible notes... - // because we don't play the lower and upper notes - // twice, we have to subtract 2 - cur_arp_idx = ( cur_frame / arp_frames ) % - ( range * 2 - 2 ); - // if greater than range, we have to play down... - // looks like the code for arp_dir==DOWN... :) - if( cur_arp_idx >= range ) - { - cur_arp_idx = range - cur_arp_idx % - ( range - 1 ) - 1; - } - } - else if( dir == RANDOM ) - { - // just pick a random chord-index - cur_arp_idx = (int)( range * ( (float) rand() / - (float) RAND_MAX ) ); - } - - // now calculate final key for our arp-note - const int sub_note_key = base_note_key + (cur_arp_idx / - cur_chord_size ) * - NOTES_PER_OCTAVE + - s_chords[selected_arp].interval[cur_arp_idx % cur_chord_size]; - - // range-checking - if( sub_note_key >= NOTES_PER_OCTAVE * OCTAVES || - sub_note_key < 0 || - engine::getMixer()->criticalXRuns() ) - { - continue; - } - - float vol_level = 1.0f; - if( _n->released() ) - { - vol_level = _n->volumeLevel( cur_frame + gated_frames ); - } - - // create new arp-note - note new_note( midiTime( 0 ), midiTime( 0 ), - static_cast( sub_note_key % - NOTES_PER_OCTAVE ), - static_cast( sub_note_key / - NOTES_PER_OCTAVE ), - static_cast( _n->getVolume() * - vol_level ), - _n->getPanning(), _n->detuning() ); - - // create sub-note-play-handle, only ptr to note is different - // and is_arp_note=TRUE - new notePlayHandle( _n->getInstrumentTrack(), - ( ( m_arpModeComboBox->value() != FREE ) ? - cnphv.first()->offset() : - _n->offset() ) + - frames_processed, - gated_frames, - new_note, - _n, TRUE ); - - // update counters - frames_processed += arp_frames; - cur_frame += arp_frames; - } - - // make sure, note is handled as arp-base-note, even if we didn't add a - // sub-note so far - if( m_arpModeComboBox->value() != FREE ) - { - _n->setArpNote( TRUE ); - } -} - - - - -void arpAndChordsTabWidget::saveSettings( QDomDocument & _doc, - QDomElement & _this ) -{ - m_chordsEnabledModel->saveSettings( _doc, _this, "chord-enabled" ); - m_chordsModel->saveSettings( _doc, _this, "chord" ); - m_chordRangeModel->saveSettings( _doc, _this, "chordrange" ); - - m_arpEnabledModel->saveSettings( _doc, _this, "arp-enabled" ); - m_arpModel->saveSettings( _doc, _this, "arp" ); - m_arpRangeModel->saveSettings( _doc, _this, "arprange" ); - m_arpTimeModel->saveSettings( _doc, _this, "arptime" ); - m_arpGateModel->saveSettings( _doc, _this, "arpgate" ); - m_arpDirectionModel->saveSettings( _doc, _this, "arpdir" ); - - m_arpModeModel->saveSettings( _doc, _this, "arpmode" ); -} - - - - -void arpAndChordsTabWidget::loadSettings( const QDomElement & _this ) -{ - m_chordsEnabledModel->loadSettings( _this, "chord-enabled" ); - m_chordsModel->loadSettings( _this, "chord" ); - m_chordRangeModel->loadSettings( _this, "chordrange" ); - - m_arpEnabledModel->loadSettings( _this, "arp-enabled" ); - m_arpModel->loadSettings( _this, "arp" ); - m_arpRangeModel->loadSettings( _this, "arprange" ); - m_arpTimeModel->loadSettings( _this, "arptime" ); - m_arpGateModel->loadSettings( _this, "arpgate" ); - m_arpDirectionModel->loadSettings( _this, "arpdir" ); - - // Keep compatibility with version 0.2.1 file format - if( _this.hasAttribute( "arpsyncmode" ) ) - { - m_arpTimeKnob->setSyncMode( - ( tempoSyncKnob::tempoSyncMode ) _this.attribute( - "arpsyncmode" ).toInt() ); - } - - m_arpModeModel->loadSettings( _this, "arpmode" ); -} - - - - - - -#include "arp_and_chords_tab_widget.moc" - - -#endif diff --git a/src/core/automation_editor.cpp b/src/core/automation_editor.cpp index e18170ed6b..be1ad3462c 100644 --- a/src/core/automation_editor.cpp +++ b/src/core/automation_editor.cpp @@ -4,7 +4,7 @@ * automation_editor.cpp - implementation of automationEditor which is used for * actual setting of dynamic values * - * Copyright (c) 2006-2007 Javier Serrano Polo + * Copyright (c) 2006-2008 Javier Serrano Polo * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -115,8 +115,8 @@ automationEditor::automationEditor( void ) : // add time-line m_timeLine = new timeLine( VALUES_WIDTH, 32, m_ppt, - engine::getSongEditor()->getPlayPos( - songEditor::PLAY_AUTOMATION_PATTERN ), + engine::getSong()->getPlayPos( + song::Mode_PlayAutomationPattern ), m_currentPosition, this ); connect( this, SIGNAL( positionChanged( const midiTime & ) ), m_timeLine, SLOT( updatePosition( const midiTime & ) ) ); @@ -612,7 +612,7 @@ void automationEditor::keyPressEvent( QKeyEvent * _ke ) break; case Qt::Key_Space: - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { stop(); } @@ -728,7 +728,7 @@ void automationEditor::mousePressEvent( QMouseEvent * _me ) QCursor c( Qt::SizeAllCursor ); QApplication::setOverrideCursor( c ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( ( _me->button() == Qt::RightButton && m_editMode == DRAW ) || @@ -739,7 +739,7 @@ void automationEditor::mousePressEvent( QMouseEvent * _me ) if( it != time_map.end() ) { m_pattern->removeValue( -it.key() ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } else if( _me->button() == Qt::LeftButton && @@ -773,7 +773,7 @@ void automationEditor::mousePressEvent( QMouseEvent * _me ) m_action = MOVE_SELECTION; - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( _me->button() == Qt::RightButton && m_editMode == MOVE ) @@ -849,7 +849,7 @@ void automationEditor::mouseMoveEvent( QMouseEvent * _me ) level ); } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( _me->buttons() & Qt::NoButton && m_editMode == DRAW ) @@ -1533,10 +1533,9 @@ void automationEditor::resizeEvent( QResizeEvent * ) m_topBottomScroll->setValue( m_scroll_level ); - if( engine::getSongEditor() ) + if( engine::getSong() ) { - engine::getSongEditor()->getPlayPos( - songEditor::PLAY_AUTOMATION_PATTERN + engine::getSong()->getPlayPos( song::Mode_PlayAutomationPattern ).m_timeLine->setFixedWidth( width() ); } m_toolBar->setFixedWidth( width() ); @@ -1614,7 +1613,7 @@ int automationEditor::getLevel( int _y ) inline bool automationEditor::inBBEditor( void ) { return( m_pattern->getTrack()->getTrackContainer() - == engine::getBBEditor() ); + == engine::getBBTrackContainer() ); } @@ -1629,23 +1628,22 @@ void automationEditor::play( void ) if( !m_pattern->getTrack() ) { - if( engine::getSongEditor()->playMode() != - songEditor::PLAY_PATTERN ) + if( engine::getSong()->playMode() != song::Mode_PlayPattern ) { - engine::getSongEditor()->stop(); - engine::getSongEditor()->playPattern( (pattern *) + engine::getSong()->stop(); + engine::getSong()->playPattern( (pattern *) engine::getPianoRoll()->currentPattern() ); m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } - else if( engine::getSongEditor()->playing() ) + else if( engine::getSong()->playing() ) { - engine::getSongEditor()->pause(); + engine::getSong()->pause(); m_playButton->setIcon( embed::getIconPixmap( "play" ) ); } - else if( engine::getSongEditor()->paused() ) + else if( engine::getSong()->paused() ) { - engine::getSongEditor()->resumeFromPause(); + engine::getSong()->resumeFromPause(); m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } @@ -1653,13 +1651,13 @@ void automationEditor::play( void ) { m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - engine::getSongEditor()->playPattern( (pattern *) + engine::getSong()->playPattern( (pattern *) engine::getPianoRoll()->currentPattern() ); } } else if( inBBEditor() ) { - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { m_playButton->setIcon( embed::getIconPixmap( "play" ) ); } @@ -1668,18 +1666,18 @@ void automationEditor::play( void ) m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } - engine::getBBEditor()->play(); + engine::getBBTrackContainer()->play(); } else { - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { - engine::getSongEditor()->pause(); + engine::getSong()->pause(); m_playButton->setIcon( embed::getIconPixmap( "play" ) ); } - else if( engine::getSongEditor()->paused() ) + else if( engine::getSong()->paused() ) { - engine::getSongEditor()->resumeFromPause(); + engine::getSong()->resumeFromPause(); m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } @@ -1687,7 +1685,7 @@ void automationEditor::play( void ) { m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - engine::getSongEditor()->play(); + engine::getSong()->play(); } } } @@ -1703,11 +1701,11 @@ void automationEditor::stop( void ) } if( m_pattern->getTrack() && inBBEditor() ) { - engine::getBBEditor()->stop(); + engine::getBBTrackContainer()->stop(); } else { - engine::getSongEditor()->stop(); + engine::getSong()->stop(); } m_playButton->setIcon( embed::getIconPixmap( "play" ) ); m_playButton->update(); @@ -1901,7 +1899,7 @@ void automationEditor::cutSelectedValues( void ) if( !selected_values.isEmpty() ) { - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); for( timeMap::iterator it = selected_values.begin(); it != selected_values.end(); ++it ) @@ -1936,7 +1934,7 @@ void automationEditor::pasteValues( void ) // we only have to do the following lines if we pasted at // least one value... - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); update(); engine::getSongEditor()->update(); } @@ -1965,7 +1963,7 @@ void automationEditor::deleteSelectedValues( void ) if( update_after_delete == TRUE ) { - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); update(); engine::getSongEditor()->update(); } @@ -1976,9 +1974,9 @@ void automationEditor::deleteSelectedValues( void ) void automationEditor::updatePosition( const midiTime & _t ) { - if( ( engine::getSongEditor()->playing() && - engine::getSongEditor()->playMode() == - songEditor::PLAY_AUTOMATION_PATTERN ) || + if( ( engine::getSong()->playing() && + engine::getSong()->playMode() == + song::Mode_PlayAutomationPattern ) || m_scrollBack == TRUE ) { const int w = width() - VALUES_WIDTH; diff --git a/src/core/automation_pattern.cpp b/src/core/automation_pattern.cpp index 3ec6033e58..ead23b6a7f 100644 --- a/src/core/automation_pattern.cpp +++ b/src/core/automation_pattern.cpp @@ -4,7 +4,7 @@ * automation_pattern.cpp - implementation of class automationPattern which * holds dynamic values * - * Copyright (c) 2006-2007 Javier Serrano Polo + * Copyright (c) 2006-2008 Javier Serrano Polo * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -31,6 +31,7 @@ #include "automation_pattern.h" #include "automation_editor.h" +#include "automatable_model_templates.h" #include "engine.h" #include "level_object.h" #include "note.h" diff --git a/src/core/bb_editor.cpp b/src/core/bb_editor.cpp index 5f758358e6..38138a446e 100644 --- a/src/core/bb_editor.cpp +++ b/src/core/bb_editor.cpp @@ -40,17 +40,280 @@ #include "engine.h" #include "main_window.h" #include "name_label.h" -#include "song_editor.h" +#include "song.h" #include "templates.h" #include "tool_button.h" #include "tooltip.h" #include "track_container.h" +bbTrackContainer::bbTrackContainer( void ) : + trackContainer(), + m_bbComboBoxModel( this ) +{ + connect( &m_bbComboBoxModel, SIGNAL( dataChanged() ), + this, SLOT( currentBBChanged() ), + Qt::QueuedConnection ); + // we *always* want to receive updates even in case BB actually did + // not change upon setCurrentBB()-call + connect( &m_bbComboBoxModel, SIGNAL( dataUnchanged() ), + this, SLOT( currentBBChanged() ), + Qt::QueuedConnection ); +} -bbEditor::bbEditor( void ) : - trackContainer() + + +bbTrackContainer::~bbTrackContainer() +{ +} + + + + +bool bbTrackContainer::play( midiTime _start, fpp_t _frames, + f_cnt_t _offset, + Sint16 _tco_num ) +{ + bool played_a_note = FALSE; + if( lengthOfBB( _tco_num ) <= 0 ) + { + return( played_a_note ); + } + + _start = ( _start.getTact() % lengthOfBB( _tco_num ) ) * 64 + + _start.getTact64th(); + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + if( tl[i]->play( _start, _frames, _offset, _tco_num ) == TRUE ) + { + played_a_note = TRUE; + } + } + + return( played_a_note ); +} + + + +/* +void bbTrackContainer::saveSettings( QDomDocument & _doc, QDomElement & _parent ) +{ + trackContainer::saveSettings( _doc, _parent ); +} + + + + +void bbTrackContainer::loadSettings( const QDomElement & _this ) +{ + trackContainer::loadSettings( _this ); +} +*/ + + + +void bbTrackContainer::updateAfterTrackAdd( void ) +{ + // make sure, new track(s) have TCOs for every beat/bassline + for( int i = 0; i < tMax( 1, numOfBBs() ); ++i ) + { + createTCOsForBB( i ); + } +} + + + + +tact bbTrackContainer::lengthOfBB( int _bb ) +{ + midiTime max_length; + + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + trackContentObject * tco = tl[i]->getTCO( _bb ); + max_length = tMax( max_length, tco->length() ); + } + if( max_length.getTact64th() == 0 ) + { + return( max_length.getTact() ); + } + + return( max_length.getTact() + 1 ); +} + + + + +int bbTrackContainer::numOfBBs( void ) const +{ + return( engine::getSong()->countTracks( track::BBTrack ) ); +} + + + + +void bbTrackContainer::removeBB( int _bb ) +{ + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + delete tl[i]->getTCO( _bb ); + tl[i]->removeTact( _bb * 64 ); + } + if( _bb <= currentBB() ) + { + setCurrentBB( tMax( currentBB() - 1, 0 ) ); + } +} + + + + +void bbTrackContainer::swapBB( int _bb1, int _bb2 ) +{ + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + tl[i]->swapPositionOfTCOs( _bb1, _bb2 ); + } + updateComboBox(); +} + + + + +void bbTrackContainer::updateBBTrack( trackContentObject * _tco ) +{ + bbTrack * t = bbTrack::findBBTrack( _tco->startPosition() / 64 ); + if( t != NULL ) + { + t->dataChanged(); + //t->getTrackContentWidget()->update(); + } +} + + + + +void bbTrackContainer::play( void ) +{ + if( engine::getSong()->playing() ) + { + if( engine::getSong()->playMode() != song::Mode_PlayBB ) + { + engine::getSong()->stop(); + engine::getSong()->playBB(); + } + else + { + engine::getSong()->pause(); + } + } + else if( engine::getSong()->paused() ) + { + engine::getSong()->resumeFromPause(); + } + else + { + engine::getSong()->playBB(); + } + +} + + + + +void bbTrackContainer::stop( void ) +{ + engine::getSong()->stop(); +} + + + + +void bbTrackContainer::updateComboBox( void ) +{ + const int cur_bb = currentBB(); + + m_bbComboBoxModel.clear(); + + for( int i = 0; i < numOfBBs(); ++i ) + { + bbTrack * bbt = bbTrack::findBBTrack( i ); + m_bbComboBoxModel.addItem( bbt->name(), + bbt->pixmap() ? new QPixmap( *bbt->pixmap() ) + : NULL ); + } + setCurrentBB( cur_bb ); +} + + + + +void bbTrackContainer::currentBBChanged( void ) +{ + // first make sure, all channels have a TCO at current BB + createTCOsForBB( currentBB() ); + + // now update all track-labels (the current one has to become white, + // the others green) + for( int i = 0; i < numOfBBs(); ++i ) + { + bbTrack::findBBTrack( i )->dataChanged(); +//trackLabel()->update(); + } + + //emit dataChanged(); + //emit positionChanged( NULL ); +} + + + + +void bbTrackContainer::createTCOsForBB( int _bb ) +{ + if( numOfBBs() == 0 || engine::getSong()->isLoadingProject() ) + { + return; + } + + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + while( tl[i]->numOfTCOs() < _bb + 1 ) + { + midiTime position = midiTime( tl[i]->numOfTCOs(), 0 ); + trackContentObject * tco = tl[i]->addTCO( + tl[i]->createTCO( position ) ); + tco->movePosition( position ); + tco->changeLength( midiTime( 1, 0 ) ); + } + } +} + + + + + + + + + + + + + + + + + + +bbEditor::bbEditor( bbTrackContainer * _tc ) : + trackContainerView( _tc ), + m_bbtc( _tc ) { // create toolbar m_toolBar = new QWidget; @@ -85,7 +348,7 @@ bbEditor::bbEditor( void ) : toolButton * add_bb_track = new toolButton( embed::getIconPixmap( "add_bb_track" ), tr( "Add beat/bassline" ), - engine::getSongEditor(), SLOT( addBBTrack() ), + engine::getSong(), SLOT( addBBTrack() ), m_toolBar ); @@ -102,15 +365,7 @@ bbEditor::bbEditor( void ) : m_bbComboBox = new comboBox( m_toolBar ); m_bbComboBox->setFixedSize( 200, 22 ); - - m_bbComboBoxModel = new comboBoxModel( /* this */ ); - m_bbComboBox->setModel( m_bbComboBoxModel ); - connect( m_bbComboBoxModel, SIGNAL( dataChanged() ), - this, SLOT( currentBBChanged() ) ); - // we *always* want to receive updates even in case BB actually did - // not change upon setCurrentBB()-call - connect( m_bbComboBoxModel, SIGNAL( dataUnchanged() ), - this, SLOT( currentBBChanged() ) ); + m_bbComboBox->setModel( &_tc->m_bbComboBoxModel ); tb_layout->addSpacing( 5 ); tb_layout->addWidget( m_playButton ); @@ -144,6 +399,12 @@ bbEditor::bbEditor( void ) : } w->show(); + + + setModel( _tc ); + connect( &_tc->m_bbComboBoxModel, SIGNAL( dataChanged() ), + this, SLOT( updatePosition() ), + Qt::QueuedConnection ); } @@ -156,123 +417,66 @@ bbEditor::~bbEditor() -void bbEditor::currentBBChanged( void ) +void bbEditor::removeBBView( int _bb ) { - // first make sure, all channels have a TCO at current BB - createTCOsForBB( currentBB() ); - - realignTracks(); - - // now update all track-labels (the current one has to become white, - // the others green) - for( int i = 0; i < numOfBBs(); ++i ) + QList tl = trackViews(); + for( int i = 0; i < tl.size(); ++i ) { - bbTrack::findBBTrack( i )->trackLabel()->update(); + tl[i]->getTrackContentWidget()->removeTCOView( _bb ); } - - emit positionChanged( NULL ); } -tact bbEditor::lengthOfBB( int _bb ) +void bbEditor::play( void ) { - midiTime max_length; - - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) + if( engine::getSong()->playing() ) { - trackContentObject * tco = tl[i]->getTCO( _bb ); - max_length = tMax( max_length, tco->length() ); - } - if( max_length.getTact64th() == 0 ) - { - return( max_length.getTact() ); - } - - return( max_length.getTact() + 1 ); -} - - - - -bool FASTCALL bbEditor::play( midiTime _start, fpp_t _frames, - f_cnt_t _offset, - Sint16 _tco_num ) -{ - bool played_a_note = FALSE; - if( lengthOfBB( _tco_num ) <= 0 ) - { - return( played_a_note ); - } - - _start = ( _start.getTact() % lengthOfBB( _tco_num ) ) * 64 + - _start.getTact64th(); - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - if( tl[i]->play( _start, _frames, _offset, _tco_num ) == TRUE ) + if( engine::getSong()->playMode() != song::Mode_PlayBB ) { - played_a_note = TRUE; + engine::getSong()->stop(); + engine::getSong()->playBB(); + m_playButton->setIcon( embed::getIconPixmap( + "pause" ) ); + } + else + { + engine::getSong()->pause(); + m_playButton->setIcon( embed::getIconPixmap( + "play" ) ); } } + else if( engine::getSong()->paused() ) + { + engine::getSong()->resumeFromPause(); + m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); + } + else + { + m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); + engine::getSong()->playBB(); + } - return( played_a_note ); } -int bbEditor::numOfBBs( void ) const +void bbEditor::stop( void ) { - return( engine::getSongEditor()->countTracks( track::BB_TRACK ) ); + engine::getSong()->stop(); + m_playButton->setIcon( embed::getIconPixmap( "play" ) ); + m_playButton->update(); } -void bbEditor::removeBB( int _bb ) +void bbEditor::updatePosition( void ) { - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - tl[i]->removeTCO( _bb ); - tl[i]->getTrackContentWidget()->removeTact( _bb * 64 ); - } - if( _bb <= currentBB() ) - { - setCurrentBB( tMax( currentBB() - 1, 0 ) ); - } -} - - - -void bbEditor::updateBBTrack( trackContentObject * _tco ) -{ - bbTrack * t = bbTrack::findBBTrack( _tco->startPosition() / 64 ); - if( t != NULL ) - { - t->getTrackContentWidget()->update(); - } -} - - - - -void bbEditor::updateComboBox( void ) -{ - const int cur_bb = currentBB(); - - m_bbComboBoxModel->clear(); - - for( int i = 0; i < numOfBBs(); ++i ) - { - bbTrack * bbt = bbTrack::findBBTrack( i ); - m_bbComboBoxModel->addItem( bbt->trackLabel()->text(), - new QPixmap( bbt->trackLabel()->pixmap() ) ); - } - setCurrentBB( cur_bb ); + //realignTracks(); + emit positionChanged( m_currentPosition ); } @@ -282,7 +486,7 @@ void bbEditor::keyPressEvent( QKeyEvent * _ke ) { if ( _ke->key() == Qt::Key_Space ) { - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { stop(); } @@ -293,16 +497,16 @@ void bbEditor::keyPressEvent( QKeyEvent * _ke ) } else if ( _ke->key() == Qt::Key_Plus ) { - if( currentBB()+ 1 < numOfBBs() ) + if( m_bbtc->currentBB()+ 1 < m_bbtc->numOfBBs() ) { - setCurrentBB( currentBB() + 1 ); + m_bbtc->setCurrentBB( m_bbtc->currentBB() + 1 ); } } else if ( _ke->key() == Qt::Key_Minus ) { - if( currentBB() > 0 ) + if( m_bbtc->currentBB() > 0 ) { - setCurrentBB( currentBB() - 1 ); + m_bbtc->setCurrentBB( m_bbtc->currentBB() - 1 ); } } else @@ -316,116 +520,6 @@ void bbEditor::keyPressEvent( QKeyEvent * _ke ) -void bbEditor::play( void ) -{ - if( engine::getSongEditor()->playing() ) - { - if( engine::getSongEditor()->playMode() != songEditor::PLAY_BB ) - { - engine::getSongEditor()->stop(); - engine::getSongEditor()->playBB(); - m_playButton->setIcon( embed::getIconPixmap( - "pause" ) ); - } - else - { - engine::getSongEditor()->pause(); - m_playButton->setIcon( embed::getIconPixmap( - "play" ) ); - } - } - else if( engine::getSongEditor()->paused() ) - { - engine::getSongEditor()->resumeFromPause(); - m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - } - else - { - m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - engine::getSongEditor()->playBB(); - } - -} - - - - -void bbEditor::stop( void ) -{ - engine::getSongEditor()->stop(); - m_playButton->setIcon( embed::getIconPixmap( "play" ) ); - m_playButton->update(); -} - - - - - - -void bbEditor::saveSettings( QDomDocument & _doc, QDomElement & _parent ) -{ - trackContainer::saveSettings( _doc, _parent ); -} - - - - -void bbEditor::loadSettings( const QDomElement & _this ) -{ - trackContainer::loadSettings( _this ); -} - - - - -void bbEditor::updateAfterTrackAdd( void ) -{ - // make sure, new track(s) have TCOs for every beat/bassline - for( int i = 0; i < tMax( 1, numOfBBs() ); ++i ) - { - createTCOsForBB( i ); - } -} - - - - -void bbEditor::createTCOsForBB( int _bb ) -{ - if( numOfBBs() == 0 ) - { - return; - } - - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - while( tl[i]->numOfTCOs() < _bb + 1 ) - { - midiTime position = midiTime( tl[i]->numOfTCOs(), 0 ); - trackContentObject * tco = tl[i]->addTCO( - tl[i]->createTCO( position ) ); - tco->movePosition( position ); - tco->changeLength( midiTime( 1, 0 ) ); - } - } -} - - - - -void bbEditor::swapBB( int _bb1, int _bb2 ) -{ - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - tl[i]->swapPositionOfTCOs( _bb1, _bb2 ); - } - updateComboBox(); -} - - - #include "bb_editor.moc" diff --git a/src/core/engine.cpp b/src/core/engine.cpp index 919571e897..fbfd03d3c7 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -38,12 +38,15 @@ #include "project_journal.h" #include "project_notes.h" #include "song_editor.h" +#include "song.h" bool engine::s_hasGUI = TRUE; float engine::s_framesPerTact64th; mixer * engine::s_mixer; mainWindow * engine::s_mainWindow; +bbTrackContainer * engine::s_bbTrackContainer; +song * engine::s_song; songEditor * engine::s_songEditor; automationEditor * engine::s_automationEditor; bbEditor * engine::s_bbEditor; @@ -63,11 +66,14 @@ void engine::init( const bool _has_gui ) loadExtensions(); s_projectJournal = new projectJournal; - s_mainWindow = new mainWindow; s_mixer = new mixer; - s_songEditor = new songEditor; + s_song = new song; + s_bbTrackContainer = new bbTrackContainer; + + s_mainWindow = new mainWindow; + s_songEditor = new songEditor( s_song ); s_projectNotes = new projectNotes; - s_bbEditor = new bbEditor; + s_bbEditor = new bbEditor( s_bbTrackContainer ); s_pianoRoll = new pianoRoll; s_automationEditor = new automationEditor; s_ladspaManager = new ladspa2LMMS; @@ -120,7 +126,7 @@ void engine::destroy( void ) void engine::updateFramesPerTact64th( void ) { s_framesPerTact64th = s_mixer->sampleRate() * 60.0f * BEATS_PER_TACT - / 64.0f / s_songEditor->getTempo(); + / 64.0f / s_song->getTempo(); } diff --git a/src/core/envelope_and_lfo_parameters.cpp b/src/core/envelope_and_lfo_parameters.cpp index 9af4fef9c1..eaddca8878 100644 --- a/src/core/envelope_and_lfo_parameters.cpp +++ b/src/core/envelope_and_lfo_parameters.cpp @@ -1,8 +1,7 @@ #ifndef SINGLE_SOURCE_COMPILE /* - * envelope_and_lfo_widget.cpp - widget which is m_used by envelope/lfo/filter- - * tab of channel-window + * envelope_and_lfo_parameters.cpp - class envelopeAndLFOParameters * * Copyright (c) 2004-2008 Tobias Doerffel * @@ -29,25 +28,12 @@ #include "envelope_and_lfo_parameters.h" -#include -#include #include - #include "debug.h" -#include "embed.h" #include "engine.h" -#include "gui_templates.h" -#include "knob.h" -#include "led_checkbox.h" #include "mmp.h" #include "oscillator.h" -#include "pixmap_button.h" -#include "song_editor.h" -#include "string_pair_drag.h" -#include "tempo_sync_knob.h" -#include "text_float.h" -#include "tooltip.h" #include "automatable_model_templates.h" @@ -58,383 +44,99 @@ const float SECS_PER_ENV_SEGMENT = 5.0f; const float SECS_PER_LFO_OSCILLATION = 20.0f; -const int ENV_GRAPH_X = 6; -const int ENV_GRAPH_Y = 6; - -const int ENV_KNOBS_Y = 43; -const int ENV_KNOBS_LBL_Y = ENV_KNOBS_Y+35; -const int KNOB_X_SPACING = 32; -const int PREDELAY_KNOB_X = 6; -const int ATTACK_KNOB_X = PREDELAY_KNOB_X+KNOB_X_SPACING; -const int HOLD_KNOB_X = ATTACK_KNOB_X+KNOB_X_SPACING; -const int DECAY_KNOB_X = HOLD_KNOB_X+KNOB_X_SPACING; -const int SUSTAIN_KNOB_X = DECAY_KNOB_X+KNOB_X_SPACING; -const int RELEASE_KNOB_X = SUSTAIN_KNOB_X+KNOB_X_SPACING; -const int AMOUNT_KNOB_X = RELEASE_KNOB_X+KNOB_X_SPACING; - -const float TIME_UNIT_WIDTH = 36.0; - - -const int LFO_GRAPH_X = 6; -const int LFO_GRAPH_Y = ENV_KNOBS_LBL_Y+14; -const int LFO_KNOB_Y = LFO_GRAPH_Y-2; -const int LFO_PREDELAY_KNOB_X = LFO_GRAPH_X + 100; -const int LFO_ATTACK_KNOB_X = LFO_PREDELAY_KNOB_X+KNOB_X_SPACING; -const int LFO_SPEED_KNOB_X = LFO_ATTACK_KNOB_X+KNOB_X_SPACING; -const int LFO_AMOUNT_KNOB_X = LFO_SPEED_KNOB_X+KNOB_X_SPACING; -const int LFO_SHAPES_X = LFO_GRAPH_X;//PREDELAY_KNOB_X; -const int LFO_SHAPES_Y = LFO_GRAPH_Y + 50; - - -QPixmap * envelopeAndLFOWidget::s_envGraph = NULL; -QPixmap * envelopeAndLFOWidget::s_lfoGraph = NULL; - -QVector envelopeAndLFOWidget::s_EaLWidgets; +QVector envelopeAndLFOParameters::s_EaLParametersInstances; -envelopeAndLFOWidget::envelopeAndLFOWidget( float _value_for_zero_amount, - QWidget * _parent, - track * _track ) : - QWidget( _parent ), +envelopeAndLFOParameters::envelopeAndLFOParameters( + float _value_for_zero_amount, + track * _track, + model * _parent ) : + model( _parent ), m_used( FALSE ), - m_predelayModel(), - m_attackModel(), - m_holdModel(), - m_decayModel(), - m_sustainModel(), - m_releaseModel(), - m_amountModel(), - m_lfoPredelayModel(), - m_lfoAttackModel(), - m_lfoSpeedModel(), - m_lfoAmountModel(), - m_lfoWaveModel(), - m_x100Model( FALSE, FALSE, TRUE ), - m_controlEnvAmountModel( FALSE, FALSE, TRUE ), + m_predelayModel( 0.0, 0.0, 1.0, 0.001, this ), + m_attackModel( 0.0, 0.0, 1.0, 0.001, this ), + m_holdModel( 0.5, 0.0, 1.0, 0.001, this ), + m_decayModel( 0.5, 0.0, 1.0, 0.001, this ), + m_sustainModel( 0.5, 0.0, 1.0, 0.001, this ), + m_releaseModel( 0.1, 0.0, 1.0, 0.001, this ), + m_amountModel( 0.0, -1.0, 1.0, 0.005, this ), m_valueForZeroAmount( _value_for_zero_amount ), m_pahdEnv( NULL ), m_rEnv( NULL ), + m_lfoPredelayModel( 0.0, 0.0, 1.0, 0.001, this ), + m_lfoAttackModel( 0.0, 0.0, 1.0, 0.001, this ), + m_lfoSpeedModel( 0.1, 0.01, 1.0, 0.0001, this ), + m_lfoAmountModel( 0.0, -1.0, 1.0, 0.005, this ), + m_lfoWaveModel( SineWave, 0, NumLfoShapes, 1, this ), + m_x100Model( FALSE, this ), + m_controlEnvAmountModel( FALSE, this ), m_lfoFrame( 0 ), m_lfoAmountIsZero( FALSE ), m_lfoShapeData( NULL ) { - if( s_envGraph == NULL ) - { - s_envGraph = new QPixmap( embed::getIconPixmap( - "envelope_graph" ) ); - } - if( s_lfoGraph == NULL ) - { - s_lfoGraph = new QPixmap( embed::getIconPixmap( "lfo_graph" ) ); - } + s_EaLParametersInstances.push_back( this ); - s_EaLWidgets.push_back( this ); m_predelayModel.setTrack( _track ); - m_predelayModel.setRange( 0.0, 1.0, 0.001 ); - m_predelayModel.setInitValue( 0.0 ); - m_predelayKnob = new knob( knobBright_26, this, tr( "Predelay-time" ) ); - m_predelayKnob->setModel( &m_predelayModel ); - m_predelayKnob->setLabel( tr( "DEL" ) ); - m_predelayKnob->move( PREDELAY_KNOB_X, ENV_KNOBS_Y ); - m_predelayKnob->setHintText( tr( "Predelay:" ) + " ", "" ); - m_predelayKnob->setWhatsThis( - tr( "Use this knob for setting predelay of the current " - "envelope. The bigger this value the longer the time " - "before start of actual envelope." ) ); + m_attackModel.setTrack( _track ); + m_holdModel.setTrack( _track ); + m_decayModel.setTrack( _track ); + m_sustainModel.setTrack( _track ); + m_releaseModel.setTrack( _track ); + m_amountModel.setTrack( _track ); + + m_lfoPredelayModel.setTrack( _track ); + m_lfoAttackModel.setTrack( _track ); + m_lfoSpeedModel.setTrack( _track ); + m_lfoAmountModel.setTrack( _track ); + m_lfoWaveModel.setTrack( _track ); + m_x100Model.setTrack( _track ); + m_controlEnvAmountModel.setTrack( _track ); + + connect( &m_predelayModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_attackModel.setTrack( _track ); - m_attackModel.setRange( 0.0, 1.0, 0.001 ); - m_attackModel.setInitValue( 0.0 ); - m_attackKnob = new knob( knobBright_26, this, tr( "Attack-time" ) ); - m_attackKnob->setModel( &m_attackModel ); - m_attackKnob->setLabel( tr( "ATT" ) ); - m_attackKnob->move( ATTACK_KNOB_X, ENV_KNOBS_Y ); - m_attackKnob->setHintText( tr( "Attack:" )+" ", "" ); - m_attackKnob->setWhatsThis( - tr( "Use this knob for setting attack-time of the current " - "envelope. The bigger this value the longer the " - "envelope needs to increase to attack-level. " - "Choose a small value for instruments like pianos " - "and a big value for strings." ) ); connect( &m_attackModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - m_holdModel.setTrack( _track ); - m_holdModel.setRange( 0.0, 1.0, 0.001 ); - m_holdModel.setInitValue( 0.5 ); - m_holdKnob = new knob( knobBright_26, this, tr( "Hold-time" ) ); - m_holdKnob->setModel( &m_holdModel ); - m_holdKnob->setLabel( tr( "HOLD" ) ); - m_holdKnob->move( HOLD_KNOB_X, ENV_KNOBS_Y ); - m_holdKnob->setHintText( tr( "Hold:" ) + " ", "" ); - m_holdKnob->setWhatsThis( - tr( "Use this knob for setting hold-time of the current " - "envelope. The bigger this value the longer the " - "envelope holds attack-level before it begins to " - "decrease to sustain-level." ) ); connect( &m_holdModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_decayModel.setTrack( _track ); - m_decayModel.setRange( 0.0, 1.0, 0.001 ); - m_decayModel.setInitValue( 0.5 ); - m_decayKnob = new knob( knobBright_26, this, tr( "Decay-time" ) ); - m_decayKnob->setModel( &m_decayModel ); - m_decayKnob->setLabel( tr( "DEC" ) ); - m_decayKnob->move( DECAY_KNOB_X, ENV_KNOBS_Y ); - m_decayKnob->setHintText( tr( "Decay:" ) + " ", "" ); - m_decayKnob->setWhatsThis( - tr( "Use this knob for setting decay-time of the current " - "envelope. The bigger this value the longer the " - "envelope needs to decrease from attack-level to " - "sustain-level. Choose a small value for instruments " - "like pianos." ) ); connect( &m_decayModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_sustainModel.setTrack( _track ); - m_sustainModel.setRange( 0.0, 1.0, 0.001 ); - m_sustainModel.setInitValue( 0.5 ); - m_sustainKnob = new knob( knobBright_26, this, tr( "Sustain-level" ) ); - m_sustainKnob->setModel( &m_sustainModel ); - m_sustainKnob->setLabel( tr( "SUST" ) ); - m_sustainKnob->move( SUSTAIN_KNOB_X, ENV_KNOBS_Y ); - m_sustainKnob->setHintText( tr( "Sustain:" ) + " ", "" ); - m_sustainKnob->setWhatsThis( - tr( "Use this knob for setting sustain-level of the current " - "envelope. The bigger this value the higher the level " - "on which the envelope stays before going down to " - "zero." ) ); connect( &m_sustainModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - - m_releaseModel.setTrack( _track ); - m_releaseModel.setRange( 0.0, 1.0, 0.001 ); - m_releaseModel.setInitValue( 0.1 ); - m_releaseKnob = new knob( knobBright_26, this, tr( "Release-time" ) ); - m_releaseKnob->setModel( &m_releaseModel ); - m_releaseKnob->setLabel( tr( "REL" ) ); - m_releaseKnob->move( RELEASE_KNOB_X, ENV_KNOBS_Y ); - m_releaseKnob->setHintText( tr( "Release:" ) + " ", "" ); - m_releaseKnob->setWhatsThis( - tr( "Use this knob for setting release-time of the current " - "envelope. The bigger this value the longer the " - "envelope needs to decrease from sustain-level to " - "zero. Choose a big value for soft instruments like " - "strings." ) ); connect( &m_releaseModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_amountModel.setTrack( _track ); - m_amountModel.setRange( -1.0, 1.0, 0.005 ); - m_amountModel.setInitValue( 0.0 ); - m_amountKnob = new knob( knobBright_26, this, - tr( "Modulation amount" ) ); - m_amountKnob->setModel( &m_amountModel ); - m_amountKnob->setLabel( tr( "AMT" ) ); - m_amountKnob->move( AMOUNT_KNOB_X, ENV_GRAPH_Y ); - m_amountKnob->setHintText( tr( "Modulation amount:" ) + " ", "" ); - m_amountKnob->setWhatsThis( - tr( "Use this knob for setting modulation amount of the " - "current envelope. The bigger this value the more the " - "according size (e.g. volume or cutoff-frequency) " - "will be influenced by this envelope." ) ); connect( &m_amountModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - - m_lfoPredelayModel.setTrack( _track ); - m_lfoPredelayModel.setRange( 0.0, 1.0, 0.001 ); - m_lfoPredelayModel.setInitValue( 0.0 ); - m_lfoPredelayKnob = new knob( knobBright_26, this, - tr( "LFO-predelay-time" ) ); - m_lfoPredelayKnob->setModel( &m_lfoPredelayModel ); - m_lfoPredelayKnob->setLabel( tr( "DEL" ) ); - m_lfoPredelayKnob->move( LFO_PREDELAY_KNOB_X, LFO_KNOB_Y ); - m_lfoPredelayKnob->setHintText( tr( "LFO-predelay:" ) + " ", "" ); - m_lfoPredelayKnob->setWhatsThis( - tr( "Use this knob for setting predelay-time of the current " - "LFO. The bigger this value the the time until the " - "LFO starts to oscillate." ) ); connect( &m_lfoPredelayModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_lfoAttackModel.setTrack( _track ); - m_lfoAttackModel.setRange( 0.0, 1.0, 0.001 ); - m_lfoAttackModel.setInitValue( 0.0 ); - m_lfoAttackKnob = new knob( knobBright_26, this, - tr( "LFO-attack-time" ) ); - m_lfoAttackKnob->setModel( &m_lfoAttackModel ); - m_lfoAttackKnob->setLabel( tr( "ATT" ) ); - m_lfoAttackKnob->move( LFO_ATTACK_KNOB_X, LFO_KNOB_Y ); - m_lfoAttackKnob->setHintText( tr( "LFO-attack:" ) + " ", "" ); - m_lfoAttackKnob->setWhatsThis( - tr( "Use this knob for setting attack-time of the current LFO. " - "The bigger this value the longer the LFO needs to " - "increase its amplitude to maximum." ) ); connect( &m_lfoAttackModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_lfoSpeedModel.setTrack( _track ); - m_lfoSpeedModel.setRange( 0.01, 1.0, 0.0001 ); - m_lfoSpeedModel.setInitValue( 0.1 ); - m_lfoSpeedKnob = new tempoSyncKnob( knobBright_26, this, - tr( "LFO-speed" ), 20000.0 ); - m_lfoSpeedKnob->setModel( &m_lfoSpeedModel ); - m_lfoSpeedKnob->setLabel( tr( "SPD" ) ); - m_lfoSpeedKnob->move( LFO_SPEED_KNOB_X, LFO_KNOB_Y ); - m_lfoSpeedKnob->setHintText( tr( "LFO-speed:" ) + " ", "" ); - m_lfoSpeedKnob->setWhatsThis( - tr( "Use this knob for setting speed of the current LFO. The " - "bigger this value the faster the LFO oscillates and " - "the faster will be your effect." ) ); connect( &m_lfoSpeedModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - m_lfoAmountModel.setTrack( _track ); - m_lfoAmountModel.setRange( -1.0, 1.0, 0.005 ); - m_lfoAmountModel.setInitValue( 0.0 ); - m_lfoAmountKnob = new knob( knobBright_26, this, - tr( "LFO-modulation-amount" ) ); - m_lfoAmountKnob->setModel( &m_lfoAmountModel ); - m_lfoAmountKnob->setLabel( tr( "AMT" ) ); - m_lfoAmountKnob->move( LFO_AMOUNT_KNOB_X, LFO_KNOB_Y ); - m_lfoAmountKnob->setHintText( tr( "Modulation amount:" ) + " ", "" ); - m_lfoAmountKnob->setWhatsThis( - tr( "Use this knob for setting modulation amount of the " - "current LFO. The bigger this value the more the " - "selected size (e.g. volume or cutoff-frequency) will " - "be influenced by this LFO." ) ); connect( &m_lfoAmountModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - - pixmapButton * sin_lfo_btn = new pixmapButton( this, NULL ); - sin_lfo_btn->move( LFO_SHAPES_X, LFO_SHAPES_Y ); - sin_lfo_btn->setActiveGraphic( embed::getIconPixmap( - "sin_wave_active" ) ); - sin_lfo_btn->setInactiveGraphic( embed::getIconPixmap( - "sin_wave_inactive" ) ); - sin_lfo_btn->setWhatsThis( - tr( "Click here if you want a sine-wave for current " - "oscillator." ) ); - - pixmapButton * triangle_lfo_btn = new pixmapButton( this, NULL ); - triangle_lfo_btn->move( LFO_SHAPES_X+15, LFO_SHAPES_Y ); - triangle_lfo_btn->setActiveGraphic( embed::getIconPixmap( - "triangle_wave_active" ) ); - triangle_lfo_btn->setInactiveGraphic( embed::getIconPixmap( - "triangle_wave_inactive" ) ); - triangle_lfo_btn->setWhatsThis( - tr( "Click here if you want a triangle-wave for current " - "oscillator." ) ); - - pixmapButton * saw_lfo_btn = new pixmapButton( this, NULL ); - saw_lfo_btn->move( LFO_SHAPES_X+30, LFO_SHAPES_Y ); - saw_lfo_btn->setActiveGraphic( embed::getIconPixmap( - "saw_wave_active" ) ); - saw_lfo_btn->setInactiveGraphic( embed::getIconPixmap( - "saw_wave_inactive" ) ); - saw_lfo_btn->setWhatsThis( - tr( "Click here if you want a saw-wave for current " - "oscillator." ) ); - - pixmapButton * sqr_lfo_btn = new pixmapButton( this, NULL ); - sqr_lfo_btn->move( LFO_SHAPES_X+45, LFO_SHAPES_Y ); - sqr_lfo_btn->setActiveGraphic( embed::getIconPixmap( - "square_wave_active" ) ); - sqr_lfo_btn->setInactiveGraphic( embed::getIconPixmap( - "square_wave_inactive" ) ); - sqr_lfo_btn->setWhatsThis( - tr( "Click here if you want a square-wave for current " - "oscillator." ) ); - - m_userLfoBtn = new pixmapButton( this, NULL ); - m_userLfoBtn->move( LFO_SHAPES_X+60, LFO_SHAPES_Y ); - m_userLfoBtn->setActiveGraphic( embed::getIconPixmap( - "usr_wave_active" ) ); - m_userLfoBtn->setInactiveGraphic( embed::getIconPixmap( - "usr_wave_inactive" ) ); - m_userLfoBtn->setWhatsThis( - tr( "Click here if you want a user-defined wave for current " - "oscillator. Afterwards drag an according sample-" - "file into LFO-graph." ) ); - - connect( m_userLfoBtn, SIGNAL( toggled( bool ) ), - this, SLOT( lfoUserWaveChanged() ) ); - - m_lfoWaveBtnGrp = new automatableButtonGroup( this, - tr( "LFO wave shape" ) ); - m_lfoWaveBtnGrp->setModel( &m_lfoWaveModel ); - m_lfoWaveBtnGrp->addButton( sin_lfo_btn ); - m_lfoWaveBtnGrp->addButton( triangle_lfo_btn ); - m_lfoWaveBtnGrp->addButton( saw_lfo_btn ); - m_lfoWaveBtnGrp->addButton( sqr_lfo_btn ); - m_lfoWaveBtnGrp->addButton( m_userLfoBtn ); - - m_lfoWaveModel.setTrack( _track ); - m_lfoWaveModel.setInitValue( SIN ); - connect( &m_lfoWaveModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); - - m_x100Model.setTrack( _track ); - m_x100Cb = new ledCheckBox( tr( "FREQ x 100" ), this, - tr( "Freq x 100" ) ); - m_x100Cb->setModel( &m_x100Model ); - m_x100Cb->setFont( pointSize<6>( m_x100Cb->font() ) ); - m_x100Cb->move( LFO_PREDELAY_KNOB_X, LFO_GRAPH_Y + 36 ); - m_x100Cb->setWhatsThis( - tr( "Click here if the frequency of this LFO should be " - "multiplied with 100." ) ); - toolTip::add( m_x100Cb, tr( "multiply LFO-frequency with 100" ) ); connect( &m_x100Model, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); + connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), + this, SLOT( updateSampleVars() ) ); - m_controlEnvAmountModel.setTrack( _track ); - m_controlEnvAmountCb = new ledCheckBox( tr( "MODULATE ENV-AMOUNT" ), - this, tr( "Modulate Env-Amount" ) ); - m_controlEnvAmountCb->setModel( &m_controlEnvAmountModel ); - m_controlEnvAmountCb->move( LFO_PREDELAY_KNOB_X, LFO_GRAPH_Y + 54 ); - m_controlEnvAmountCb->setFont( pointSize<6>( - m_controlEnvAmountCb->font() ) ); - m_controlEnvAmountCb ->setWhatsThis( - tr( "Click here to make the envelope-amount controlled by this " - "LFO." ) ); - toolTip::add( m_controlEnvAmountCb, - tr( "control envelope-amount by this LFO" ) ); - - - setAcceptDrops( TRUE ); - - connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), this, - SLOT( updateSampleVars() ) ); m_lfoShapeData = new sample_t[engine::getMixer()->framesPerPeriod()]; + updateSampleVars(); } -envelopeAndLFOWidget::~envelopeAndLFOWidget() +envelopeAndLFOParameters::~envelopeAndLFOParameters() { m_predelayModel.disconnect( this ); m_attackModel.disconnect( this ); @@ -454,19 +156,17 @@ envelopeAndLFOWidget::~envelopeAndLFOWidget() delete[] m_rEnv; delete[] m_lfoShapeData; - QVector & v = s_EaLWidgets; + QVector & v = s_EaLParametersInstances; if( qFind( v.begin(), v.end(), this ) != v.end() ) { v.erase( qFind( v.begin(), v.end(), this ) ); } - - delete m_lfoWaveBtnGrp; } -inline sample_t envelopeAndLFOWidget::lfoShapeSample( fpp_t _frame_offset ) +inline sample_t envelopeAndLFOParameters::lfoShapeSample( fpp_t _frame_offset ) { f_cnt_t frame = ( m_lfoFrame + _frame_offset ) % m_lfoOscillationFrames; const float phase = frame / static_cast( @@ -474,19 +174,19 @@ inline sample_t envelopeAndLFOWidget::lfoShapeSample( fpp_t _frame_offset ) sample_t shape_sample; switch( m_lfoWaveModel.value() ) { - case TRIANGLE: + case TriangleWave: shape_sample = oscillator::triangleSample( phase ); break; - case SQUARE: + case SquareWave: shape_sample = oscillator::squareSample( phase ); break; - case SAW: + case SawWave: shape_sample = oscillator::sawSample( phase ); break; - case USER: + case UserDefinedWave: shape_sample = m_userWave.userWaveSample( phase ); break; - case SIN: + case SineWave: default: shape_sample = oscillator::sinSample( phase ); break; @@ -497,7 +197,7 @@ inline sample_t envelopeAndLFOWidget::lfoShapeSample( fpp_t _frame_offset ) -void envelopeAndLFOWidget::updateLFOShapeData( void ) +void envelopeAndLFOParameters::updateLFOShapeData( void ) { const fpp_t frames = engine::getMixer()->framesPerPeriod(); for( fpp_t offset = 0; offset < frames; ++offset ) @@ -510,10 +210,10 @@ void envelopeAndLFOWidget::updateLFOShapeData( void ) -void envelopeAndLFOWidget::triggerLFO( void ) +void envelopeAndLFOParameters::triggerLFO( void ) { - QVector & v = s_EaLWidgets; - for( QVector::iterator it = v.begin(); + QVector & v = s_EaLParametersInstances; + for( QVector::iterator it = v.begin(); it != v.end(); ++it ) { ( *it )->m_lfoFrame += @@ -525,10 +225,10 @@ void envelopeAndLFOWidget::triggerLFO( void ) -void envelopeAndLFOWidget::resetLFO( void ) +void envelopeAndLFOParameters::resetLFO( void ) { - QVector & v = s_EaLWidgets; - for( QVector::iterator it = v.begin(); + QVector & v = s_EaLParametersInstances; + for( QVector::iterator it = v.begin(); it != v.end(); ++it ) { ( *it )->m_lfoFrame = 0; @@ -539,7 +239,7 @@ void envelopeAndLFOWidget::resetLFO( void ) -inline void FASTCALL envelopeAndLFOWidget::fillLFOLevel( float * _buf, +inline void FASTCALL envelopeAndLFOParameters::fillLFOLevel( float * _buf, f_cnt_t _frame, const fpp_t _frames ) { @@ -573,7 +273,7 @@ inline void FASTCALL envelopeAndLFOWidget::fillLFOLevel( float * _buf, -void FASTCALL envelopeAndLFOWidget::fillLevel( float * _buf, f_cnt_t _frame, +void FASTCALL envelopeAndLFOParameters::fillLevel( float * _buf, f_cnt_t _frame, const f_cnt_t _release_begin, const fpp_t _frames ) { @@ -619,7 +319,7 @@ void FASTCALL envelopeAndLFOWidget::fillLevel( float * _buf, f_cnt_t _frame, -void envelopeAndLFOWidget::saveSettings( QDomDocument & _doc, +void envelopeAndLFOParameters::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { m_predelayModel.saveSettings( _doc, _parent, "pdel" ); @@ -642,7 +342,7 @@ void envelopeAndLFOWidget::saveSettings( QDomDocument & _doc, -void envelopeAndLFOWidget::loadSettings( const QDomElement & _this ) +void envelopeAndLFOParameters::loadSettings( const QDomElement & _this ) { m_predelayModel.loadSettings( _this, "pdel" ); m_attackModel.loadSettings( _this, "att" ); @@ -658,14 +358,15 @@ void envelopeAndLFOWidget::loadSettings( const QDomElement & _this ) m_lfoAmountModel.loadSettings( _this, "lamt" ); m_x100Model.loadSettings( _this, "x100" ); m_controlEnvAmountModel.loadSettings( _this, "ctlenvamt" ); - - // Keep compatibility with version 2.1 file format + + // ### TODO: +/* // Keep compatibility with version 2.1 file format if( _this.hasAttribute( "lfosyncmode" ) ) { m_lfoSpeedKnob->setSyncMode( ( tempoSyncKnob::tempoSyncMode ) _this.attribute( "lfosyncmode" ).toInt() ); - } + }*/ m_userWave.setAudioFile( _this.attribute( "userwavefile" ) ); @@ -675,229 +376,7 @@ void envelopeAndLFOWidget::loadSettings( const QDomElement & _this ) -void envelopeAndLFOWidget::mousePressEvent( QMouseEvent * _me ) -{ - if( _me->button() != Qt::LeftButton ) - { - return; - } - - if( QRect( ENV_GRAPH_X, ENV_GRAPH_Y, s_envGraph->width(), - s_envGraph->height() ).contains( _me->pos() ) == TRUE ) - { - if( m_amountKnob->value() < 1.0f ) - { - m_amountKnob->setValue( 1.0f ); - } - else - { - m_amountKnob->setValue( 0.0f ); - } - updateSampleVars(); - } - else if( QRect( LFO_GRAPH_X, LFO_GRAPH_Y, s_lfoGraph->width(), - s_lfoGraph->height() ).contains( _me->pos() ) == TRUE ) - { - if( m_lfoAmountKnob->value() < 1.0f ) - { - m_lfoAmountKnob->setValue( 1.0f ); - } - else - { - m_lfoAmountKnob->setValue( 0.0f ); - } - updateSampleVars(); - } -} - - - - -void envelopeAndLFOWidget::dragEnterEvent( QDragEnterEvent * _dee ) -{ - stringPairDrag::processDragEnterEvent( _dee, - QString( "samplefile,tco_%1" ).arg( - track::SAMPLE_TRACK ) ); -} - - - - -void envelopeAndLFOWidget::dropEvent( QDropEvent * _de ) -{ - QString type = stringPairDrag::decodeKey( _de ); - QString value = stringPairDrag::decodeValue( _de ); - if( type == "samplefile" ) - { - m_userWave.setAudioFile( stringPairDrag::decodeValue( _de ) ); - m_userLfoBtn->model()->setValue( TRUE ); - _de->accept(); - } - else if( type == QString( "tco_%1" ).arg( track::SAMPLE_TRACK ) ) - { - multimediaProject mmp( value, FALSE ); - m_userWave.setAudioFile( mmp.content().firstChild().toElement(). - attribute( "src" ) ); - m_userLfoBtn->model()->setValue( TRUE ); - _de->accept(); - } -} - - - - -void envelopeAndLFOWidget::paintEvent( QPaintEvent * ) -{ - QPainter p( this ); - p.setRenderHint( QPainter::Antialiasing ); - - // set smaller font - p.setFont( pointSize<6>( p.font() ) ); - - // draw envelope-graph - p.drawPixmap( ENV_GRAPH_X, ENV_GRAPH_Y, *s_envGraph ); - // draw LFO-graph - p.drawPixmap( LFO_GRAPH_X, LFO_GRAPH_Y, *s_lfoGraph ); - - - p.setFont( pointSize<8>( p.font() ) ); - - const float gray_amount = 1.0f - fabsf( m_amountKnob->value() ); - - p.setPen( QPen( QColor( static_cast( 96 * gray_amount ), - static_cast( 255 - 159 * gray_amount ), - static_cast( 128 - 32 * gray_amount ) ), - 2 ) ); - - const QColor end_points_color( 0xFF, 0xBF, 0x22 ); - const QColor end_points_bg_color( 0, 0, 2 ); - - const int y_base = ENV_GRAPH_Y + s_envGraph->height() - 3; - const int avail_height = s_envGraph->height() - 6; - - int x1 = ENV_GRAPH_X + 2 + static_cast( m_predelayKnob->value() * - TIME_UNIT_WIDTH ); - int x2 = x1 + static_cast( m_attackKnob->value() * - TIME_UNIT_WIDTH ); - - p.drawLine( x1, y_base, x2, y_base - avail_height ); - p.fillRect( x1 - 1, y_base - 2, 4, 4, end_points_bg_color ); - p.fillRect( x1, y_base - 1, 2, 2, end_points_color ); - x1 = x2; - x2 = x1 + static_cast( m_holdKnob->value() * TIME_UNIT_WIDTH ); - - p.drawLine( x1, y_base - avail_height, x2, y_base - avail_height ); - p.fillRect( x1 - 1, y_base - 2 - avail_height, 4, 4, - end_points_bg_color ); - p.fillRect( x1, y_base-1-avail_height, 2, 2, end_points_color ); - x1 = x2; - x2 = x1 + static_cast( ( m_decayKnob->value() * - m_sustainKnob->value() ) * - TIME_UNIT_WIDTH ); - - p.drawLine( x1, y_base-avail_height, x2, static_cast( y_base - - avail_height + - m_sustainKnob->value() * avail_height ) ); - p.fillRect( x1 - 1, y_base - 2 - avail_height, 4, 4, - end_points_bg_color ); - p.fillRect( x1, y_base - 1 - avail_height, 2, 2, end_points_color ); - x1 = x2; - x2 = x1 + static_cast( m_releaseKnob->value() * TIME_UNIT_WIDTH ); - - p.drawLine( x1, static_cast( y_base - avail_height + - m_sustainKnob->value() * - avail_height ), x2, y_base ); - p.fillRect( x1-1, static_cast( y_base - avail_height + - m_sustainKnob->value() * - avail_height ) - 2, 4, 4, - end_points_bg_color ); - p.fillRect( x1, static_cast( y_base - avail_height + - m_sustainKnob->value() * - avail_height ) - 1, 2, 2, - end_points_color ); - p.fillRect( x2 - 1, y_base - 2, 4, 4, end_points_bg_color ); - p.fillRect( x2, y_base - 1, 2, 2, end_points_color ); - - - int LFO_GRAPH_W = s_lfoGraph->width() - 6; // substract border - int LFO_GRAPH_H = s_lfoGraph->height() - 6; // substract border - int graph_x_base = LFO_GRAPH_X + 3; - int graph_y_base = LFO_GRAPH_Y + 3 + LFO_GRAPH_H / 2; - - const float frames_for_graph = SECS_PER_LFO_OSCILLATION * - engine::getMixer()->sampleRate() / 10; - - const float lfo_gray_amount = 1.0f - fabsf( m_lfoAmountKnob->value() ); - p.setPen( QPen( QColor( static_cast( 96 * lfo_gray_amount ), - static_cast( 255 - 159 * lfo_gray_amount ), - static_cast( 128 - 32 * - lfo_gray_amount ) ), - 1.5 ) ); - - - float osc_frames = m_lfoOscillationFrames; - - if( m_x100Model.value() ) - { - osc_frames *= 100.0f; - } - - float old_y = 0; - for( int x = 0; x <= LFO_GRAPH_W; ++x ) - { - float val = 0.0; - float cur_sample = x * frames_for_graph / LFO_GRAPH_W; - if( static_cast( cur_sample ) > m_lfoPredelayFrames ) - { - float phase = ( cur_sample -= m_lfoPredelayFrames ) / - osc_frames; - switch( m_lfoWaveModel.value() ) - { - case SIN: - val = oscillator::sinSample( phase ); - break; - case TRIANGLE: - val = oscillator::triangleSample( - phase ); - break; - case SAW: - val = oscillator::sawSample( phase ); - break; - case SQUARE: - val = oscillator::squareSample( phase ); - break; - case USER: - val = m_userWave.userWaveSample( - phase ); - } - if( static_cast( cur_sample ) <= - m_lfoAttackFrames ) - { - val *= cur_sample / m_lfoAttackFrames; - } - } - float cur_y = -LFO_GRAPH_H / 2.0f * val; - p.drawLine( QLineF( graph_x_base + x - 1, graph_y_base + old_y, - graph_x_base + x, - graph_y_base + cur_y ) ); - old_y = cur_y; - } - - p.setPen( QColor( 255, 192, 0 ) ); - int ms_per_osc = static_cast( SECS_PER_LFO_OSCILLATION * - m_lfoSpeedKnob->value() * - 1000.0f ); - p.drawText( LFO_GRAPH_X + 4, LFO_GRAPH_Y + s_lfoGraph->height() - 6, - tr( "ms/LFO:" ) ); - p.drawText( LFO_GRAPH_X + 52, LFO_GRAPH_Y + s_lfoGraph->height() - 6, - QString::number( ms_per_osc ) ); - -} - - - - -void envelopeAndLFOWidget::updateSampleVars( void ) +void envelopeAndLFOParameters::updateSampleVars( void ) { engine::getMixer()->lock(); @@ -906,20 +385,20 @@ void envelopeAndLFOWidget::updateSampleVars( void ) // TODO: Remove the expKnobVals, time should be linear const f_cnt_t predelay_frames = static_cast( frames_per_env_seg * - expKnobVal( m_predelayKnob->value() ) ); + expKnobVal( m_predelayModel.value() ) ); const f_cnt_t attack_frames = static_cast( frames_per_env_seg * - expKnobVal( m_attackKnob->value() ) ); + expKnobVal( m_attackModel.value() ) ); const f_cnt_t hold_frames = static_cast( frames_per_env_seg * - expKnobVal( m_holdKnob->value() ) ); + expKnobVal( m_holdModel.value() ) ); const f_cnt_t decay_frames = static_cast( frames_per_env_seg * - expKnobVal( m_decayKnob->value() * - m_sustainKnob->value() ) ); + expKnobVal( m_decayModel.value() * + m_sustainModel.value() ) ); - m_sustainLevel = 1.0f - m_sustainKnob->value(); - m_amount = m_amountKnob->value(); + m_sustainLevel = 1.0f - m_sustainModel.value(); + m_amount = m_amountModel.value(); if( m_amount >= 0 ) { m_amountAdd = ( 1.0f - m_amount ) * m_valueForZeroAmount; @@ -932,7 +411,7 @@ void envelopeAndLFOWidget::updateSampleVars( void ) m_pahdFrames = predelay_frames + attack_frames + hold_frames + decay_frames; m_rFrames = static_cast( frames_per_env_seg * - expKnobVal( m_releaseKnob->value() ) ); + expKnobVal( m_releaseModel.value() ) ); if( static_cast( floorf( m_amount * 1000.0f ) ) == 0 ) { @@ -988,17 +467,17 @@ void envelopeAndLFOWidget::updateSampleVars( void ) const float frames_per_lfo_oscillation = SECS_PER_LFO_OSCILLATION * engine::getMixer()->sampleRate(); m_lfoPredelayFrames = static_cast( frames_per_lfo_oscillation * - expKnobVal( m_lfoPredelayKnob->value() ) ); + expKnobVal( m_lfoPredelayModel.value() ) ); m_lfoAttackFrames = static_cast( frames_per_lfo_oscillation * - expKnobVal( m_lfoAttackKnob->value() ) ); + expKnobVal( m_lfoAttackModel.value() ) ); m_lfoOscillationFrames = static_cast( frames_per_lfo_oscillation * - m_lfoSpeedKnob->value() ); + m_lfoSpeedModel.value() ); if( m_x100Model.value() ) { m_lfoOscillationFrames /= 100; } - m_lfoAmount = m_lfoAmountKnob->value() * 0.5f; + m_lfoAmount = m_lfoAmountModel.value() * 0.5f; m_used = TRUE; if( static_cast( floorf( m_lfoAmount * 1000.0f ) ) == 0 ) @@ -1016,7 +495,7 @@ void envelopeAndLFOWidget::updateSampleVars( void ) m_bad_lfoShapeData = TRUE; - update(); + emit dataChanged(); engine::getMixer()->unlock(); } @@ -1024,22 +503,6 @@ void envelopeAndLFOWidget::updateSampleVars( void ) -void envelopeAndLFOWidget::lfoUserWaveChanged( void ) -{ - if( m_lfoWaveModel.value() == USER ) - { - if( m_userWave.frames() <= 1 ) - { - textFloat::displayMessage( tr( "Hint" ), - tr( "Drag a sample from somewhere and drop " - "it in this window." ), - embed::getIconPixmap( "hint" ), 3000 ); - } - } -} - - - #include "envelope_and_lfo_parameters.moc" diff --git a/src/core/export_project_dialog.cpp b/src/core/export_project_dialog.cpp index 02e7f460b0..192de0da5e 100644 --- a/src/core/export_project_dialog.cpp +++ b/src/core/export_project_dialog.cpp @@ -35,7 +35,7 @@ #include "export_project_dialog.h" -#include "song_editor.h" +#include "song.h" #include "main_window.h" #include "combobox.h" #include "led_checkbox.h" @@ -243,7 +243,7 @@ void exportProjectDialog::keyPressEvent( QKeyEvent * _ke ) { if( _ke->key() == Qt::Key_Escape ) { - if( engine::getSongEditor()->exporting() == FALSE ) + if( engine::getSong()->exporting() == FALSE ) { accept(); } @@ -259,7 +259,7 @@ void exportProjectDialog::keyPressEvent( QKeyEvent * _ke ) void exportProjectDialog::closeEvent( QCloseEvent * _ce ) { - if( engine::getSongEditor()->exporting() == TRUE ) + if( engine::getSong()->exporting() == TRUE ) { abortProjectExport(); _ce->ignore(); @@ -359,21 +359,20 @@ void exportProjectDialog::exportBtnClicked( void ) engine::getMixer()->setAudioDevice( dev, m_hqmCb->model()->value() ); - engine::getSongEditor()->startExport(); + engine::getSong()->startExport(); delete m_hqmCb; - songEditor::playPos & pp = engine::getSongEditor()->getPlayPos( - songEditor::PLAY_SONG ); + song::playPos & pp = engine::getSong()->getPlayPos( + song::Mode_PlaySong ); - while( engine::getSongEditor()->exportDone() == FALSE && - engine::getSongEditor()->exporting() == TRUE + while( engine::getSong()->exportDone() == FALSE && + engine::getSong()->exporting() == TRUE && !m_deleteFile ) { dev->processNextBuffer(); int pval = pp * 100 / - ( ( engine::getSongEditor()->lengthInTacts() + 1 ) - * 64 ); + ( ( engine::getSong()->lengthInTacts() + 1 ) * 64 ); m_exportProgressBar->setValue( pval ); // update lmms-main-win-caption engine::getMainWindow()->setWindowTitle( tr( "Rendering:" ) @@ -391,7 +390,7 @@ void exportProjectDialog::exportBtnClicked( void ) void exportProjectDialog::cancelBtnClicked( void ) { // is song-export-thread active? - if( engine::getSongEditor()->exporting() == TRUE ) + if( engine::getSong()->exporting() == TRUE ) { // then dispose abort of export abortProjectExport(); @@ -425,7 +424,7 @@ void exportProjectDialog::finishProjectExport( void ) // restore window-title engine::getMainWindow()->resetWindowTitle(); - engine::getSongEditor()->stopExport(); + engine::getSong()->stopExport(); // if we rendered file from command line, quit after export if( file_to_render != "" ) diff --git a/src/core/file_browser.cpp b/src/core/file_browser.cpp index e32c57b4ba..0f413daa39 100644 --- a/src/core/file_browser.cpp +++ b/src/core/file_browser.cpp @@ -48,7 +48,7 @@ #include "mmp.h" #include "preset_preview_play_handle.h" #include "sample_play_handle.h" -#include "song_editor.h" +#include "song.h" #include "string_pair_drag.h" #include "text_float.h" @@ -261,14 +261,14 @@ void listView::activateListItem( QTreeWidgetItem * _item, int _column ) return; } - if( f->type() == fileItem::SAMPLE_FILE ) + if( f->type() == fileItem::SampleFile ) { // samples are per default opened in bb-editor because they're // likely drum-samples etc. engine::getMixer()->lock(); instrumentTrack * it = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, - engine::getBBEditor() ) ); + track::create( track::InstrumentTrack, + engine::getBBTrackContainer() ) ); #ifdef LMMS_DEBUG assert( it != NULL ); #endif @@ -278,31 +278,31 @@ void listView::activateListItem( QTreeWidgetItem * _item, int _column ) { afp->setParameter( "samplefile", f->fullName() ); } - it->toggledInstrumentTrackButton( TRUE ); + //it->toggledInstrumentTrackButton( TRUE ); engine::getMixer()->unlock(); } - else if( f->type() == fileItem::PRESET_FILE ) + else if( f->type() == fileItem::PresetFile ) { // presets are per default opened in bb-editor multimediaProject mmp( f->fullName() ); engine::getMixer()->lock(); instrumentTrack * it = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, - engine::getBBEditor() ) ); + track::create( track::InstrumentTrack, + engine::getBBTrackContainer() ) ); if( it != NULL ) { it->loadTrackSpecificSettings( mmp.content(). firstChild(). toElement() ); - it->toggledInstrumentTrackButton( TRUE ); + //it->toggledInstrumentTrackButton( TRUE ); } engine::getMixer()->unlock(); } - else if( f->type() == fileItem::PROJECT_FILE ) + else if( f->type() == fileItem::ProjectFile ) { if( engine::getMainWindow()->mayChangeProject() ) { - engine::getSongEditor()->loadProject( f->fullName() ); + engine::getSong()->loadProject( f->fullName() ); } } } @@ -326,16 +326,16 @@ void listView::sendToActiveInstrumentTrack( void ) // instrument-track while( w.hasPrevious() ) { - instrumentTrack * ct = dynamic_cast( + instrumentTrackView * itv = dynamic_cast( w.previous()->widget() ); - if( ct != NULL && ct->isHidden() == FALSE ) + if( itv != NULL && itv->isHidden() == FALSE ) { // ok, it's an instrument-track, so we can apply the // sample or the preset engine::getMixer()->lock(); - if( m_contextMenuItem->type() == fileItem::SAMPLE_FILE ) + if( m_contextMenuItem->type() == fileItem::SampleFile ) { - instrument * afp = ct->loadInstrument( + instrument * afp = itv->model()->loadInstrument( engine::sampleExtensions() [m_contextMenuItem ->extension()] ); @@ -346,15 +346,15 @@ void listView::sendToActiveInstrumentTrack( void ) } } else if( m_contextMenuItem->type() == - fileItem::PRESET_FILE ) + fileItem::PresetFile ) { multimediaProject mmp( m_contextMenuItem->fullName() ); - ct->loadTrackSpecificSettings( mmp.content(). - firstChild(). + itv->model()->loadTrackSpecificSettings( + mmp.content().firstChild(). toElement() ); } - ct->toggledInstrumentTrackButton( TRUE ); + //ct->toggledInstrumentTrackButton( TRUE ); engine::getMixer()->unlock(); break; } @@ -367,10 +367,10 @@ void listView::sendToActiveInstrumentTrack( void ) void listView::openInNewInstrumentTrack( trackContainer * _tc ) { engine::getMixer()->lock(); - if( m_contextMenuItem->type() == fileItem::SAMPLE_FILE ) + if( m_contextMenuItem->type() == fileItem::SampleFile ) { instrumentTrack * ct = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, _tc ) ); + track::create( track::InstrumentTrack, _tc ) ); #ifdef LMMS_DEBUG assert( ct != NULL ); #endif @@ -383,19 +383,19 @@ void listView::openInNewInstrumentTrack( trackContainer * _tc ) afp->setParameter( "samplefile", m_contextMenuItem->fullName() ); } - ct->toggledInstrumentTrackButton( TRUE ); + //ct->toggledInstrumentTrackButton( TRUE ); } - else if( m_contextMenuItem->type() == fileItem::PRESET_FILE ) + else if( m_contextMenuItem->type() == fileItem::PresetFile ) { multimediaProject mmp( m_contextMenuItem->fullName() ); - track * t = track::create( track::INSTRUMENT_TRACK, _tc ); + track * t = track::create( track::InstrumentTrack, _tc ); instrumentTrack * ct = dynamic_cast( t ); if( ct != NULL ) { ct->loadTrackSpecificSettings( mmp.content(). firstChild(). toElement() ); - ct->toggledInstrumentTrackButton( TRUE ); + //ct->toggledInstrumentTrackButton( TRUE ); } } engine::getMixer()->unlock(); @@ -406,7 +406,7 @@ void listView::openInNewInstrumentTrack( trackContainer * _tc ) void listView::openInNewInstrumentTrackBBE( void ) { - openInNewInstrumentTrack( engine::getBBEditor() ); + openInNewInstrumentTrack( engine::getBBTrackContainer() ); } @@ -414,7 +414,7 @@ void listView::openInNewInstrumentTrackBBE( void ) void listView::openInNewInstrumentTrackSE( void ) { - openInNewInstrumentTrack( engine::getSongEditor() ); + openInNewInstrumentTrack( engine::getSong() ); } @@ -435,8 +435,8 @@ void listView::updateDirectory( QTreeWidgetItem * _item ) void listView::contextMenuEvent( QContextMenuEvent * _e ) { fileItem * f = dynamic_cast( itemAt( _e->pos() ) ); - if( f != NULL && ( f->type() == fileItem::SAMPLE_FILE || - f->type() == fileItem::PRESET_FILE ) ) + if( f != NULL && ( f->type() == fileItem::SampleFile || + f->type() == fileItem::PresetFile ) ) { m_contextMenuItem = f; QMenu contextMenu( this ); @@ -495,7 +495,7 @@ void listView::mousePressEvent( QMouseEvent * _me ) m_previewPlayHandle ); m_previewPlayHandle = NULL; } - if( f->type() == fileItem::SAMPLE_FILE ) + if( f->type() == fileItem::SampleFile ) { textFloat * tf = textFloat::displayMessage( tr( "Loading sample" ), @@ -510,7 +510,7 @@ void listView::mousePressEvent( QMouseEvent * _me ) m_previewPlayHandle = s; delete tf; } - else if( f->type() == fileItem::PRESET_FILE ) + else if( f->type() == fileItem::PresetFile ) { m_previewPlayHandle = new presetPreviewPlayHandle( f->fullName() ); @@ -539,7 +539,7 @@ void listView::mouseMoveEvent( QMouseEvent * _me ) { switch( f->type() ) { - case fileItem::PRESET_FILE: + case fileItem::PresetFile: new stringPairDrag( "presetfile", f->fullName(), embed::getIconPixmap( @@ -547,7 +547,7 @@ void listView::mouseMoveEvent( QMouseEvent * _me ) this ); break; - case fileItem::SAMPLE_FILE: + case fileItem::SampleFile: new stringPairDrag( "samplefile", f->fullName(), embed::getIconPixmap( @@ -555,7 +555,7 @@ void listView::mouseMoveEvent( QMouseEvent * _me ) this ); break; - case fileItem::MIDI_FILE: + case fileItem::MidiFile: new stringPairDrag( "midifile", f->fullName(), embed::getIconPixmap( @@ -842,22 +842,22 @@ void fileItem::initPixmapStuff( void ) switch( m_type ) { - case PROJECT_FILE: + case ProjectFile: setIcon( 0, *s_projectFilePixmap ); break; - case PRESET_FILE: + case PresetFile: setIcon( 0, *s_presetFilePixmap ); break; - case SAMPLE_FILE: + case SampleFile: setIcon( 0, *s_sampleFilePixmap ); break; - case MIDI_FILE: + case MidiFile: setIcon( 0, *s_midiFilePixmap ); break; - case FLP_FILE: + case FlpFile: setIcon( 0, *s_flpFilePixmap ); break; - case UNKNOWN: + case UnknownFile: default: setIcon( 0, *s_unknownFilePixmap ); break; @@ -872,44 +872,44 @@ void fileItem::determineFileType( void ) QString ext = extension(); if( ext == "mmp" || ext == "mpt" || ext == "mmpz" ) { - m_type = PROJECT_FILE; + m_type = ProjectFile; } else if( ext == "xml" ) { - multimediaProject::projectTypes t = + multimediaProject::ProjectTypes t = multimediaProject::typeOfFile( fullName() ); - if( t == multimediaProject::SONG_PROJECT ) + if( t == multimediaProject::SongProject ) { - m_type = PROJECT_FILE; + m_type = ProjectFile; } - else if( t == multimediaProject::INSTRUMENT_TRACK_SETTINGS ) + else if( t == multimediaProject::InstrumentTrackSettings ) { - m_type = PRESET_FILE; + m_type = PresetFile; } else { - m_type = UNKNOWN; + m_type = UnknownFile; } } else if( ext == "csf" ) { - m_type = PRESET_FILE; + m_type = PresetFile; } else if( engine::sampleExtensions().contains( ext ) ) { - m_type = SAMPLE_FILE; + m_type = SampleFile; } else if( ext == "mid" ) { - m_type = MIDI_FILE; + m_type = MidiFile; } else if( ext == "flp" ) { - m_type = FLP_FILE; + m_type = FlpFile; } else { - m_type = UNKNOWN; + m_type = UnknownFile; } } diff --git a/src/core/import_filter.cpp b/src/core/import_filter.cpp index 640b26e4dd..1a5a18ebc5 100644 --- a/src/core/import_filter.cpp +++ b/src/core/import_filter.cpp @@ -31,6 +31,7 @@ #include "engine.h" #include "track_container.h" #include "project_journal.h" +#include "automatable_model_templates.h" diff --git a/src/core/instrument.cpp b/src/core/instrument.cpp index aedb4fb9dc..e2037e3a61 100644 --- a/src/core/instrument.cpp +++ b/src/core/instrument.cpp @@ -82,7 +82,7 @@ f_cnt_t instrument::beatLen( notePlayHandle * ) const instrument * instrument::instantiate( const QString & _plugin_name, instrumentTrack * _instrument_track ) { - plugin * p = plugin::instantiate( _plugin_name, /*_instrument_track*/ NULL, + plugin * p = plugin::instantiate( _plugin_name, _instrument_track, _instrument_track ); // check whether instantiated plugin is an instrument if( dynamic_cast( p ) != NULL ) @@ -155,9 +155,10 @@ void instrumentView::setModel( ::model * _model, bool ) if( dynamic_cast( _model ) != NULL ) { modelView::setModel( _model ); - if( dynamic_cast( parentWidget() ) != NULL ) + if( dynamic_cast( parentWidget() ) != + NULL ) { - dynamic_cast( parentWidget() )-> + dynamic_cast( parentWidget() )-> setWindowIcon( *( model()-> getDescriptor()->logo ) ); } diff --git a/src/core/instrument_functions.cpp b/src/core/instrument_functions.cpp new file mode 100644 index 0000000000..f2369766e0 --- /dev/null +++ b/src/core/instrument_functions.cpp @@ -0,0 +1,540 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * instrument_functions.cpp - models for instrument-function-tab + * + * Copyright (c) 2004-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include + + +#include "instrument_functions.h" +#include "embed.h" +#include "engine.h" +#include "instrument_track.h" +#include "note_play_handle.h" +#include "preset_preview_play_handle.h" + + + +chordCreator::chord chordCreator::s_chordTable[] = +{ + { chordCreator::tr( "octave" ), { 0, -1 } }, + { chordCreator::tr( "Major" ), { 0, 4, 7, -1 } }, + { chordCreator::tr( "Majb5" ), { 0, 4, 6, -1 } }, + { chordCreator::tr( "minor" ), { 0, 3, 7, -1 } }, + { chordCreator::tr( "minb5" ), { 0, 3, 6, -1 } }, + { chordCreator::tr( "sus2" ), { 0, 2, 7, -1 } }, + { chordCreator::tr( "sus4" ), { 0, 5, 7, -1 } }, + { chordCreator::tr( "aug" ), { 0, 4, 8, -1 } }, + { chordCreator::tr( "augsus4" ), { 0, 5, 8, -1 } }, + { chordCreator::tr( "tri" ), { 0, 3, 6, 9, -1 } }, + + { chordCreator::tr( "6" ), { 0, 4, 7, 9, -1 } }, + { chordCreator::tr( "6sus4" ), { 0, 5, 7, 9, -1 } }, + { chordCreator::tr( "6add9" ), { 0, 4, 7, 12, -1 } }, + { chordCreator::tr( "m6" ), { 0, 3, 7, 9, -1 } }, + { chordCreator::tr( "m6add9" ), { 0, 3, 7, 9, 14, -1 } }, + + { chordCreator::tr( "7" ), { 0, 4, 7, 10, -1 } }, + { chordCreator::tr( "7sus4" ), { 0, 5, 7, 10, -1 } }, + { chordCreator::tr( "7#5" ), { 0, 4, 8, 10, -1 } }, + { chordCreator::tr( "7b5" ), { 0, 4, 6, 10, -1 } }, + { chordCreator::tr( "7#9" ), { 0, 4, 7, 10, 13, 18, -1 } }, + { chordCreator::tr( "7b9" ), { 0, 4, 7, 10, 13, 16, -1 } }, + { chordCreator::tr( "7#5#9" ), { 0, 4, 8, 12, 14, 19, -1 } }, + { chordCreator::tr( "7#5b9" ), { 0, 4, 8, 12, 14, 17, -1 } }, + { chordCreator::tr( "7b5b9" ), { 0, 4, 6, 10, 12, 15, -1 } }, + { chordCreator::tr( "7add11" ), { 0, 4, 7, 10, 17, -1 } }, + { chordCreator::tr( "7add13" ), { 0, 4, 7, 10, 21, -1 } }, + { chordCreator::tr( "7#11" ), { 0, 4, 7, 10, 18, -1 } }, + { chordCreator::tr( "Maj7" ), { 0, 4, 7, 11, -1 } }, + { chordCreator::tr( "Maj7b5" ), { 0, 4, 6, 11, -1 } }, + { chordCreator::tr( "Maj7#5" ), { 0, 4, 8, 11, -1 } }, + { chordCreator::tr( "Maj7#11" ), { 0, 4, 7, 11, 18, -1 } }, + { chordCreator::tr( "Maj7add13" ), { 0, 4, 7, 11, 21, -1 } }, + { chordCreator::tr( "m7" ), { 0, 3, 7, 10, -1 } }, + { chordCreator::tr( "m7b5" ), { 0, 3, 6, 10, -1 } }, + { chordCreator::tr( "m7b9" ), { 0, 3, 7, 10, 13, -1 } }, + { chordCreator::tr( "m7add11" ), { 0, 3, 7, 10, 17, -1 } }, + { chordCreator::tr( "m7add13" ), { 0, 3, 7, 10, 21, -1 } }, + { chordCreator::tr( "m-Maj7" ), { 0, 3, 7, 11, -1 } }, + { chordCreator::tr( "m-Maj7add11" ), { 0, 3, 7, 11, 17, -1 } }, + { chordCreator::tr( "m-Maj7add13" ), { 0, 3, 7, 11, 21, -1 } }, + + { chordCreator::tr( "9" ), { 0, 4, 7, 10, 14, -1 } }, + { chordCreator::tr( "9sus4" ), { 0, 5, 7, 10, 14, -1 } }, + { chordCreator::tr( "add9" ), { 0, 4, 7, 14, -1 } }, + { chordCreator::tr( "9#5" ), { 0, 4, 8, 10, 14, -1 } }, + { chordCreator::tr( "9b5" ), { 0, 4, 6, 10, 14, -1 } }, + { chordCreator::tr( "9#11" ), { 0, 4, 7, 10, 14, 18, -1 } }, + { chordCreator::tr( "9b13" ), { 0, 4, 7, 10, 14, 20, -1 } }, + { chordCreator::tr( "Maj9" ), { 0, 4, 7, 11, 14, -1 } }, + { chordCreator::tr( "Maj9sus4" ), { 0, 5, 7, 11, 15, -1 } }, + { chordCreator::tr( "Maj9#5" ), { 0, 4, 8, 11, 14, -1 } }, + { chordCreator::tr( "Maj9#11" ), { 0, 4, 7, 11, 14, 18, -1 } }, + { chordCreator::tr( "m9" ), { 0, 3, 7, 10, 14, -1 } }, + { chordCreator::tr( "madd9" ), { 0, 3, 7, 14, -1 } }, + { chordCreator::tr( "m9b5" ), { 0, 3, 6, 10, 14, -1 } }, + { chordCreator::tr( "m9-Maj7" ), { 0, 3, 7, 11, 14, -1 } }, + + { chordCreator::tr( "11" ), { 0, 4, 7, 10, 14, 17, -1 } }, + { chordCreator::tr( "11b9" ), { 0, 4, 7, 10, 13, 17, -1 } }, + { chordCreator::tr( "Maj11" ), { 0, 4, 7, 11, 14, 17, -1 } }, + { chordCreator::tr( "m11" ), { 0, 3, 7, 10, 14, 17, -1 } }, + { chordCreator::tr( "m-Maj11" ), { 0, 3, 7, 11, 14, 17, -1 } }, + + { chordCreator::tr( "13" ), { 0, 4, 7, 10, 14, 21, -1 } }, + { chordCreator::tr( "13#9" ), { 0, 4, 7, 10, 15, 21, -1 } }, + { chordCreator::tr( "13b9" ), { 0, 4, 7, 10, 13, 21, -1 } }, + { chordCreator::tr( "13b5b9" ), { 0, 4, 6, 10, 13, 21, -1 } }, + { chordCreator::tr( "Maj13" ), { 0, 4, 7, 11, 14, 21, -1 } }, + { chordCreator::tr( "m13" ), { 0, 3, 7, 10, 14, 21, -1 } }, + { chordCreator::tr( "m-Maj13" ), { 0, 3, 7, 11, 14, 21, -1 } }, + + { chordCreator::tr( "Major" ), { 0, 2, 4, 5, 7, 9, 11, -1 } }, + { chordCreator::tr( "Harmonic minor" ), { 0, 2, 3, 5, 7, 8, + 11, -1 } }, + { chordCreator::tr( "Melodic minor" ), { 0, 2, 3, 5, 7, 9, + 11, -1 } }, + { chordCreator::tr( "Whole tone" ), { 0, 2, 4, 6, 8, 10, + -1 } }, + { chordCreator::tr( "Diminished" ), { 0, 2, 3, 5, 6, 8, 9, + 11, -1 } }, + { chordCreator::tr( "Major pentatonic" ), { 0, 2, 4, 7, 10, + -1 } }, + { chordCreator::tr( "Minor pentatonic" ), { 0, 3, 5, 7, 10, + -1 } }, + { chordCreator::tr( "Jap in sen" ), { 0, 1, 5, 7, 10, -1 } }, + { chordCreator::tr( "Major bebop" ), { 0, 2, 4, 5, 7, 8, 9, + 11, -1 } }, + { chordCreator::tr( "Dominant bebop" ), { 0, 2, 4, 5, 7, 9, + 10, 11, -1 } }, + { chordCreator::tr( "Blues" ), { 0, 3, 5, 6, 7, 10, -1 } }, + { chordCreator::tr( "Arabic" ), { 0, 1, 4, 5, 7, 8, 11, -1 } }, + { chordCreator::tr( "Enigmatic" ), { 0, 1, 4, 6, 8, 10, 11, + -1 } }, + { chordCreator::tr( "Neopolitan" ), { 0, 1, 3, 5, 7, 9, 11, + -1 } }, + { chordCreator::tr( "Neopolitan minor" ), { 0, 1, 3, 5, 7, 9, + 11, -1 } }, + { chordCreator::tr( "Hungarian minor" ), { 0, 2, 3, 6, 7, 9, + 11, -1 } }, + { chordCreator::tr( "Dorian" ), { 0, 2, 3, 5, 7, 9, 10, -1 } }, + { chordCreator::tr( "Phrygolydian" ), { 0, 1, 3, 5, 7, 8, 10, + -1 } }, + { chordCreator::tr( "Lydian" ), { 0, 2, 4, 6, 7, 9, 11, -1 } }, + { chordCreator::tr( "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, + -1 } }, + { chordCreator::tr( "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, + -1 } }, + { chordCreator::tr( "Locrian" ), { 0, 1, 3, 5, 6, 8, 10, + -1 } }, + + { "", { -1, -1 } } + +} ; + + +const int CHORDS_GROUPBOX_X = 4; +const int CHORDS_GROUPBOX_Y = 5; +const int CHORDS_GROUPBOX_WIDTH = 238; +const int CHORDS_GROUPBOX_HEIGHT = 65; +const int ARP_GROUPBOX_X = CHORDS_GROUPBOX_X; +const int ARP_GROUPBOX_Y = 10 + CHORDS_GROUPBOX_Y + CHORDS_GROUPBOX_HEIGHT; +const int ARP_GROUPBOX_WIDTH = CHORDS_GROUPBOX_WIDTH; +const int ARP_GROUPBOX_HEIGHT = 240 - ARP_GROUPBOX_Y; + + + +chordCreator::chordCreator( instrumentTrack * _instrument_track ) : + model( _instrument_track ), + m_chordsEnabledModel( FALSE, this ), + m_chordsModel( this ), + m_chordRangeModel( 1.0f, 1.0f, 9.0f, 1.0f, this ) +{ + m_chordsEnabledModel.setTrack( _instrument_track ); + + m_chordsModel.setTrack( _instrument_track ); + for( int i = 0; s_chordTable[i].interval[0] != -1; ++i ) + { + m_chordsModel.addItem( tr( s_chordTable[i].name.toAscii(). + constData() ) ); + } + + m_chordRangeModel.setTrack( _instrument_track ); + +} + + + + +chordCreator::~chordCreator() +{ +} + + + + +void chordCreator::processNote( notePlayHandle * _n ) +{ + const int base_note_key = _n->key(); + // we add chord-subnotes to note if either note is a base-note and + // arpeggio is not used or note is part of an arpeggio + // at the same time we only add sub-notes if nothing of the note was + // played yet, because otherwise we would add chord-subnotes every + // time an audio-buffer is rendered... + if( ( ( _n->baseNote() && + _n->getInstrumentTrack()->arpeggiatorEnabled() == FALSE ) || + _n->arpNote() ) && + _n->totalFramesPlayed() == 0 && + m_chordsEnabledModel.value() == TRUE ) + { + // then insert sub-notes for chord + const int selected_chord = m_chordsModel.value(); + + for( int octave_cnt = 0; + octave_cnt < m_chordRangeModel.value(); ++octave_cnt ) + { + const int sub_note_key_base = base_note_key + + octave_cnt * NOTES_PER_OCTAVE; + // if octave_cnt == 1 we're in the first octave and + // the base-note is already done, so we don't have to + // create it in the following loop, then we loop until + // there's a -1 in the interval-array + for( int i = ( octave_cnt == 0 ) ? 1 : 0; + s_chordTable[selected_chord].interval[i] != -1; + ++i ) + { + // add interval to sub-note-key + const int sub_note_key = sub_note_key_base + + (int) s_chordTable[ + selected_chord].interval[i]; + // maybe we're out of range -> let's get outta + // here! + if( sub_note_key > NOTES_PER_OCTAVE*OCTAVES ) + { + break; + } + // create copy of base-note + note note_copy( _n->length(), 0, + (tones)( sub_note_key % + NOTES_PER_OCTAVE ), + (octaves)( sub_note_key / + NOTES_PER_OCTAVE ), + _n->getVolume(), + _n->getPanning(), + _n->detuning() ); + // create sub-note-play-handle, only note is + // different + new notePlayHandle( _n->getInstrumentTrack(), + _n->offset(), + _n->frames(), note_copy, + _n ); + } + } + } + + +} + + + + +void chordCreator::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + m_chordsEnabledModel.saveSettings( _doc, _this, "chord-enabled" ); + m_chordsModel.saveSettings( _doc, _this, "chord" ); + m_chordRangeModel.saveSettings( _doc, _this, "chordrange" ); +} + + + + +void chordCreator::loadSettings( const QDomElement & _this ) +{ + m_chordsEnabledModel.loadSettings( _this, "chord-enabled" ); + m_chordsModel.loadSettings( _this, "chord" ); + m_chordRangeModel.loadSettings( _this, "chordrange" ); +} + + + + + + + +arpeggiator::arpeggiator( instrumentTrack * _instrument_track ) : + model( _instrument_track ), + m_arpEnabledModel( FALSE ), + m_arpModel( this ), + m_arpRangeModel( 1.0f, 1.0f, 9.0f, 1.0f, this ), + m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, this ), + m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this ), + m_arpDirectionModel( 0, 0, 0, intModel::defaultRelStep(), this ), + m_arpModeModel( this ) +{ + m_arpEnabledModel.setTrack( _instrument_track ); + + m_arpModel.setTrack( _instrument_track ); + for( int i = 0; chordCreator::s_chordTable[i].interval[0] != -1; ++i ) + { + m_arpModel.addItem( tr( chordCreator::s_chordTable[i]. + name.toAscii().constData() ) ); + } + + m_arpRangeModel.setTrack( _instrument_track ); + + m_arpTimeModel.setTrack( _instrument_track ); + + m_arpGateModel.setTrack( _instrument_track ); + + m_arpDirectionModel.setTrack( _instrument_track ); + m_arpDirectionModel.setInitValue( ArpDirUp ); + + m_arpModeModel.setTrack( _instrument_track ); + m_arpModeModel.addItem( tr( "Free" ), new QPixmap( + embed::getIconPixmap( "arp_free" ) ) ); + m_arpModeModel.addItem( tr( "Sort" ), new QPixmap( + embed::getIconPixmap( "arp_sort" ) ) ); + m_arpModeModel.addItem( tr( "Sync" ), new QPixmap( + embed::getIconPixmap( "arp_sync" ) ) ); +} + + + + +arpeggiator::~arpeggiator() +{ +} + + + + +void arpeggiator::processNote( notePlayHandle * _n ) +{ + const int base_note_key = _n->key(); + if( _n->baseNote() == FALSE || + !m_arpEnabledModel.value() || + ( _n->released() && _n->releaseFramesDone() >= + _n->actualReleaseFramesToDo() ) ) + { + return; + } + + + const int selected_arp = m_arpModel.value(); + + constNotePlayHandleVector cnphv = notePlayHandle::nphsOfInstrumentTrack( + _n->getInstrumentTrack() ); + if( m_arpModeModel.value() != FreeMode && cnphv.size() == 0 ) + { + // maybe we're playing only a preset-preview-note? + cnphv = presetPreviewPlayHandle::nphsOfInstrumentTrack( + _n->getInstrumentTrack() ); + if( cnphv.size() == 0 ) + { + // still nothing found here, so lets return + //return; + cnphv.push_back( _n ); + } + } + + const int cur_chord_size = chordCreator::getChordSize( + chordCreator::s_chordTable[selected_arp] ); + const int range = (int)( cur_chord_size * m_arpRangeModel.value() ); + const int total_range = range * cnphv.size(); + + // number of frames that every note should be played + const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f * + engine::getMixer()->sampleRate() ); + const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() * + arp_frames / 100.0f ); + + // used for calculating remaining frames for arp-note, we have to add + // arp_frames-1, otherwise the first arp-note will not be setup + // correctly... -> arp_frames frames silence at the start of every note! + int cur_frame = ( ( m_arpModeModel.value() != FreeMode ) ? + cnphv.first()->totalFramesPlayed() : + _n->totalFramesPlayed() ) + arp_frames - 1; + // used for loop + f_cnt_t frames_processed = 0; + + while( frames_processed < engine::getMixer()->framesPerPeriod() ) + { + const f_cnt_t remaining_frames_for_cur_arp = arp_frames - + ( cur_frame % arp_frames ); + // does current arp-note fill whole audio-buffer? + if( remaining_frames_for_cur_arp > + engine::getMixer()->framesPerPeriod() ) + { + // then we don't have to do something! + break; + } + + frames_processed += remaining_frames_for_cur_arp; + + // init with zero + int cur_arp_idx = 0; + + // in sorted mode: is it our turn or do we have to be quiet for + // now? + if( m_arpModeModel.value() == SortMode && + ( ( cur_frame / arp_frames ) % total_range ) / + range != (f_cnt_t) _n->index() ) + { + // update counters + frames_processed += arp_frames; + cur_frame += arp_frames; + continue; + } + + const int dir = m_arpDirectionModel.value(); + // process according to arpeggio-direction... + if( dir == ArpDirUp ) + { + cur_arp_idx = ( cur_frame / arp_frames ) % range; + } + else if( dir == ArpDirDown ) + { + cur_arp_idx = range - ( cur_frame / arp_frames ) % + range - 1; + } + else if( dir == ArpDirUpAndDown && range > 1 ) + { + // imagine, we had to play the arp once up and then + // once down -> makes 2 * range possible notes... + // because we don't play the lower and upper notes + // twice, we have to subtract 2 + cur_arp_idx = ( cur_frame / arp_frames ) % + ( range * 2 - 2 ); + // if greater than range, we have to play down... + // looks like the code for arp_dir==DOWN... :) + if( cur_arp_idx >= range ) + { + cur_arp_idx = range - cur_arp_idx % + ( range - 1 ) - 1; + } + } + else if( dir == ArpDirRandom ) + { + // just pick a random chord-index + cur_arp_idx = (int)( range * ( (float) rand() / + (float) RAND_MAX ) ); + } + + // now calculate final key for our arp-note + const int sub_note_key = base_note_key + (cur_arp_idx / + cur_chord_size ) * + NOTES_PER_OCTAVE + + chordCreator::s_chordTable[selected_arp]. + interval[cur_arp_idx % cur_chord_size]; + + // range-checking + if( sub_note_key >= NOTES_PER_OCTAVE * OCTAVES || + sub_note_key < 0 || + engine::getMixer()->criticalXRuns() ) + { + continue; + } + + float vol_level = 1.0f; + if( _n->released() ) + { + vol_level = _n->volumeLevel( cur_frame + gated_frames ); + } + + // create new arp-note + note new_note( midiTime( 0 ), midiTime( 0 ), + static_cast( sub_note_key % + NOTES_PER_OCTAVE ), + static_cast( sub_note_key / + NOTES_PER_OCTAVE ), + static_cast( _n->getVolume() * + vol_level ), + _n->getPanning(), _n->detuning() ); + + // create sub-note-play-handle, only ptr to note is different + // and is_arp_note=TRUE + new notePlayHandle( _n->getInstrumentTrack(), + ( ( m_arpModeModel.value() != FreeMode ) ? + cnphv.first()->offset() : + _n->offset() ) + + frames_processed, + gated_frames, + new_note, + _n, TRUE ); + + // update counters + frames_processed += arp_frames; + cur_frame += arp_frames; + } + + // make sure, note is handled as arp-base-note, even if we didn't add a + // sub-note so far + if( m_arpModeModel.value() != FreeMode ) + { + _n->setArpNote( TRUE ); + } +} + + + + +void arpeggiator::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + m_arpEnabledModel.saveSettings( _doc, _this, "arp-enabled" ); + m_arpModel.saveSettings( _doc, _this, "arp" ); + m_arpRangeModel.saveSettings( _doc, _this, "arprange" ); + m_arpTimeModel.saveSettings( _doc, _this, "arptime" ); + m_arpGateModel.saveSettings( _doc, _this, "arpgate" ); + m_arpDirectionModel.saveSettings( _doc, _this, "arpdir" ); + + m_arpModeModel.saveSettings( _doc, _this, "arpmode" ); +} + + + + +void arpeggiator::loadSettings( const QDomElement & _this ) +{ + m_arpEnabledModel.loadSettings( _this, "arp-enabled" ); + m_arpModel.loadSettings( _this, "arp" ); + m_arpRangeModel.loadSettings( _this, "arprange" ); + m_arpTimeModel.loadSettings( _this, "arptime" ); + m_arpGateModel.loadSettings( _this, "arpgate" ); + m_arpDirectionModel.loadSettings( _this, "arpdir" ); +/* + // Keep compatibility with version 0.2.1 file format + if( _this.hasAttribute( "arpsyncmode" ) ) + { + m_arpTimeKnob->setSyncMode( + ( tempoSyncKnob::tempoSyncMode ) _this.attribute( + "arpsyncmode" ).toInt() ); + }*/ + + m_arpModeModel.loadSettings( _this, "arpmode" ); +} + + +#endif diff --git a/src/core/instrument_midi_io.cpp b/src/core/instrument_midi_io.cpp index 5767cf5aa9..ca7e88bd64 100644 --- a/src/core/instrument_midi_io.cpp +++ b/src/core/instrument_midi_io.cpp @@ -1,10 +1,9 @@ #ifndef SINGLE_SOURCE_COMPILE /* - * midi_tab_widget.cpp - tab-widget in channel-track-window for setting up - * MIDI-related stuff + * instrument_midi_io.cpp - class instrumentMidiIO * - * Copyright (c) 2005-2007 Tobias Doerffel + * Copyright (c) 2005-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -27,123 +26,56 @@ #include -#include -#include #include "instrument_midi_io.h" -#include "embed.h" #include "engine.h" -#include "gui_templates.h" #include "instrument_track.h" #include "midi_client.h" #include "midi_port.h" -#include "led_checkbox.h" -#include "lcd_spinbox.h" -#include "song_editor.h" -#include "tab_widget.h" -#include "tooltip.h" +#include "song.h" #include "automatable_model_templates.h" -midiTabWidget::midiTabWidget( instrumentTrack * _instrument_track, +instrumentMidiIO::instrumentMidiIO( instrumentTrack * _instrument_track, midiPort * _port ) : - QWidget( _instrument_track->tabWidgetParent() ), + model( _instrument_track ), m_instrumentTrack( _instrument_track ), m_midiPort( _port ), - m_inputChannelModel(), - m_outputChannelModel(), - m_receiveEnabledModel( FALSE, FALSE, TRUE ), - m_sendEnabledModel( FALSE, FALSE, TRUE ), - m_defaultVelocityInEnabledModel( FALSE, FALSE, TRUE ), - m_defaultVelocityOutEnabledModel( FALSE, FALSE, TRUE ), - m_readablePorts( NULL ), - m_writeablePorts( NULL ) + m_inputChannelModel( m_midiPort->inputChannel() + 1, + 0, MIDI_CHANNEL_COUNT, + intModel::defaultRelStep(), this ), + m_outputChannelModel( m_midiPort->outputChannel() + 1, + 1, MIDI_CHANNEL_COUNT, + intModel::defaultRelStep(), this ), + m_receiveEnabledModel( FALSE, this ), + m_sendEnabledModel( FALSE, this ), + m_defaultVelocityInEnabledModel( FALSE, this ), + m_defaultVelocityOutEnabledModel( FALSE, this ) { - m_setupTabWidget = new tabWidget( tr( "MIDI-SETUP FOR THIS CHANNEL" ), - this ); - m_setupTabWidget->setGeometry( 4, 5, 238, 200 ); - m_inputChannelModel.setTrack( m_instrumentTrack ); - m_inputChannelModel.setRange( 0, MIDI_CHANNEL_COUNT ); - m_inputChannelModel.setValue( m_midiPort->inputChannel() + 1 ); + m_outputChannelModel.setTrack( m_instrumentTrack ); + m_receiveEnabledModel.setTrack( m_instrumentTrack ); + m_defaultVelocityInEnabledModel.setTrack( m_instrumentTrack ); + m_sendEnabledModel.setTrack( m_instrumentTrack ); + m_defaultVelocityOutEnabledModel.setTrack( m_instrumentTrack ); + connect( &m_inputChannelModel, SIGNAL( dataChanged() ), this, SLOT( inputChannelChanged() ) ); - - m_inputChannelSpinBox = new lcdSpinBox( 3, m_setupTabWidget, - tr( "Input channel" ) ); - m_inputChannelSpinBox->setModel( &m_inputChannelModel ); - m_inputChannelSpinBox->addTextForValue( 0, "---" ); - m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); - m_inputChannelSpinBox->move( 28, 52 ); - m_inputChannelSpinBox->setEnabled( FALSE ); - inputChannelChanged(); - - - - m_outputChannelModel.setTrack( m_instrumentTrack ); - m_outputChannelModel.setRange( 1, MIDI_CHANNEL_COUNT ); - m_outputChannelModel.setValue( m_midiPort->outputChannel() + 1 ); connect( &m_outputChannelModel, SIGNAL( dataChanged() ), this, SLOT( outputChannelChanged() ) ); - - m_outputChannelSpinBox = new lcdSpinBox( 3, m_setupTabWidget, - tr( "Output channel" ) ); - m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); - m_outputChannelSpinBox->move( 28, 132 ); - m_outputChannelSpinBox->setEnabled( FALSE ); - outputChannelChanged(); - - - m_receiveEnabledModel.setTrack( m_instrumentTrack ); - m_receiveCheckBox = new ledCheckBox( tr( "Receive MIDI-events" ), - m_setupTabWidget, - tr( "Receive MIDI-events" ) ); - m_receiveCheckBox->setModel( &m_receiveEnabledModel ); - m_receiveCheckBox->move( 10, 34 ); - // enabling/disabling widgets is UI-stuff thus we do not use model here - connect( m_receiveCheckBox, SIGNAL( toggled( bool ) ), - m_inputChannelSpinBox, SLOT( setEnabled( bool ) ) ); connect( &m_receiveEnabledModel, SIGNAL( dataChanged() ), - this, SLOT( midiPortModeChanged() ) ); - - - m_defaultVelocityInEnabledModel.setTrack( m_instrumentTrack ); - m_defaultVelocityInCheckBox = new ledCheckBox( tr( "Default velocity " - "for all input-events" ), - m_setupTabWidget, - tr( "Default input velocity" ) ); - m_defaultVelocityInCheckBox->setModel( - &m_defaultVelocityInEnabledModel ); - m_defaultVelocityInCheckBox->move( 28, 84 ); + this, SLOT( midiPortModeChanged() ) ); connect( &m_defaultVelocityInEnabledModel, SIGNAL( dataChanged() ), - this, SLOT( defaultVelInChanged() ) ); - - - m_sendEnabledModel.setTrack( m_instrumentTrack ); - m_sendCheckBox = new ledCheckBox( tr( "Send MIDI-events" ), - m_setupTabWidget, - tr( "Send MIDI-events" ) ); - m_sendCheckBox->setModel( &m_sendEnabledModel ); - m_sendCheckBox->move( 10, 114 ); - connect( m_sendCheckBox, SIGNAL( toggled( bool ) ), - m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) ); + this, SLOT( defaultVelInChanged() ) ); connect( &m_sendEnabledModel, SIGNAL( dataChanged() ), - this, SLOT( midiPortModeChanged() ) ); - - - m_defaultVelocityOutEnabledModel.setTrack( m_instrumentTrack ); - m_defaultVelocityOutCheckBox = new ledCheckBox( tr( "Default velocity " - "for all output-events" ), - m_setupTabWidget, - tr( "Default output velocity" ) ); - m_defaultVelocityOutCheckBox->setModel( - &m_defaultVelocityOutEnabledModel ); - m_defaultVelocityOutCheckBox->move( 28, 164 ); + this, SLOT( midiPortModeChanged() ) ); connect( &m_defaultVelocityOutEnabledModel, SIGNAL( dataChanged() ), this, SLOT( defaultVelOutChanged() ) ); + inputChannelChanged(); + outputChannelChanged(); const midiPort::modes m = m_midiPort->mode(); @@ -157,38 +89,9 @@ midiTabWidget::midiTabWidget( instrumentTrack * _instrument_track, midiClient * mc = engine::getMixer()->getMIDIClient(); if( mc->isRaw() == FALSE ) { - m_readablePorts = new QMenu( m_setupTabWidget ); - m_readablePorts->setFont( pointSize<9>( - m_readablePorts->font() ) ); - connect( m_readablePorts, SIGNAL( triggered( QAction * ) ), - this, SLOT( activatedReadablePort( QAction * ) ) ); - - m_writeablePorts = new QMenu( m_setupTabWidget ); - m_writeablePorts->setFont( pointSize<9>( - m_writeablePorts->font() ) ); - connect( m_writeablePorts, SIGNAL( triggered( QAction * ) ), - this, SLOT( activatedWriteablePort( QAction * ) ) ); - - // fill menus readablePortsChanged(); writeablePortsChanged(); - QToolButton * rp_btn = new QToolButton( m_setupTabWidget ); - rp_btn->setText( tr( "MIDI-devices to receive " - "MIDI-events from" ) ); - rp_btn->setIcon( embed::getIconPixmap( "midi_in" ) ); - rp_btn->setGeometry( 186, 34, 40, 40 ); - rp_btn->setMenu( m_readablePorts ); - rp_btn->setPopupMode( QToolButton::InstantPopup ); - - QToolButton * wp_btn = new QToolButton( m_setupTabWidget ); - wp_btn->setText( tr( "MIDI-devices to send MIDI-events " - "to" ) ); - wp_btn->setIcon( embed::getIconPixmap( "midi_out" ) ); - wp_btn->setGeometry( 186, 114, 40, 40 ); - wp_btn->setMenu( m_writeablePorts ); - wp_btn->setPopupMode( QToolButton::InstantPopup ); - // we want to get informed about port-changes! mc->connectRPChanged( this, SLOT( readablePortsChanged() ) ); mc->connectWPChanged( this, SLOT( writeablePortsChanged() ) ); @@ -198,14 +101,14 @@ midiTabWidget::midiTabWidget( instrumentTrack * _instrument_track, -midiTabWidget::~midiTabWidget() +instrumentMidiIO::~instrumentMidiIO() { } -void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void instrumentMidiIO::saveSettings( QDomDocument & _doc, QDomElement & _this ) { m_inputChannelModel.saveSettings( _doc, _this, "inputchannel" ); m_outputChannelModel.saveSettings( _doc, _this, "outputchannel" ); @@ -214,17 +117,15 @@ void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) m_defaultVelocityInEnabledModel.saveSettings( _doc, _this, "defvelin" ); m_defaultVelocityOutEnabledModel.saveSettings( _doc, _this, "defvelout" ); - if( m_readablePorts != NULL && m_receiveEnabledModel.value() == TRUE ) + if( m_receiveEnabledModel.value() == TRUE ) { - // TODO: M/V-split! QString rp; - QList actions = m_readablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_readablePorts.begin(); + it != m_readablePorts.end(); ++it ) { - if( ( *it )->isChecked() ) + if( it->second ) { - rp += ( *it )->text() + ","; + rp += it->first + ","; } } // cut off comma @@ -235,17 +136,15 @@ void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) _this.setAttribute( "inports", rp ); } - if( m_writeablePorts != NULL && m_sendEnabledModel.value() == TRUE ) + if( m_sendEnabledModel.value() == TRUE ) { - // TODO: M/V-split! QString wp; - QList actions = m_writeablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_writeablePorts.begin(); + it != m_writeablePorts.end(); ++it ) { - if( ( *it )->isChecked() ) + if( it->second ) { - wp += ( *it )->text() + ","; + wp += it->first + ","; } } // cut off comma @@ -260,7 +159,7 @@ void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) -void midiTabWidget::loadSettings( const QDomElement & _this ) +void instrumentMidiIO::loadSettings( const QDomElement & _this ) { m_inputChannelModel.loadSettings( _this, "inputchannel" ); m_outputChannelModel.loadSettings( _this, "outputchannel" ); @@ -271,35 +170,29 @@ void midiTabWidget::loadSettings( const QDomElement & _this ) // restore connections - if( m_readablePorts != NULL && m_receiveEnabledModel.value() == TRUE ) + if( m_receiveEnabledModel.value() == TRUE ) { - // TODO: M/V-split! QStringList rp = _this.attribute( "inports" ).split( ',' ); - QList actions = m_readablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_readablePorts.begin(); + it != m_readablePorts.end(); ++it ) { - if( ( *it )->isChecked() != - ( rp.indexOf( ( *it )->text() ) != -1 ) ) + if( it->second != ( rp.indexOf( it->first ) != -1 ) ) { - ( *it )->setChecked( TRUE ); + it->second = TRUE; activatedReadablePort( *it ); } } } - if( m_writeablePorts != NULL && m_sendEnabledModel.value() == TRUE ) + if( m_sendEnabledModel.value() == TRUE ) { - // TODO: M/V-split! QStringList wp = _this.attribute( "outports" ).split( ',' ); - QList actions = m_writeablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_writeablePorts.begin(); + it != m_writeablePorts.end(); ++it ) { - if( ( *it )->isChecked() != - ( wp.indexOf( ( *it )->text() ) != -1 ) ) + if( it->second != ( wp.indexOf( it->first ) != -1 ) ) { - ( *it )->setChecked( TRUE ); + it->second = TRUE; activatedWriteablePort( *it ); } } @@ -309,25 +202,25 @@ void midiTabWidget::loadSettings( const QDomElement & _this ) -void midiTabWidget::inputChannelChanged( void ) +void instrumentMidiIO::inputChannelChanged( void ) { m_midiPort->setInputChannel( m_inputChannelModel.value() - 1 ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } -void midiTabWidget::outputChannelChanged( void ) +void instrumentMidiIO::outputChannelChanged( void ) { m_midiPort->setOutputChannel( m_outputChannelModel.value() - 1 ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } -void midiTabWidget::defaultVelInChanged( void ) +void instrumentMidiIO::defaultVelInChanged( void ) { m_midiPort->enableDefaultVelocityForInEvents( m_defaultVelocityInEnabledModel.value() ); @@ -336,7 +229,7 @@ void midiTabWidget::defaultVelInChanged( void ) -void midiTabWidget::defaultVelOutChanged( void ) +void instrumentMidiIO::defaultVelOutChanged( void ) { m_midiPort->enableDefaultVelocityForOutEvents( m_defaultVelocityOutEnabledModel.value() ); @@ -345,7 +238,7 @@ void midiTabWidget::defaultVelOutChanged( void ) -void midiTabWidget::midiPortModeChanged( void ) +void instrumentMidiIO::midiPortModeChanged( void ) { // this small lookup-table makes everything easier static const midiPort::modes modeTable[2][2] = @@ -357,130 +250,122 @@ void midiTabWidget::midiPortModeChanged( void ) [m_sendEnabledModel.value()] ); // check whether we have to dis-check items in connection-menu - if( m_readablePorts != NULL && m_receiveEnabledModel.value() == FALSE ) + if( m_receiveEnabledModel.value() == FALSE ) { - QList actions = m_readablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_readablePorts.begin(); + it != m_readablePorts.end(); ++it ) { - if( ( *it )->isChecked() == TRUE ) + if( it->second == TRUE ) { - ( *it )->setChecked( FALSE ); + it->second = FALSE; activatedReadablePort( *it ); } } } - if( m_writeablePorts != NULL && m_sendEnabledModel.value() == FALSE ) + if( m_sendEnabledModel.value() == FALSE ) { - QList actions = m_writeablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_writeablePorts.begin(); + it != m_writeablePorts.end(); ++it ) { - if( ( *it )->isChecked() == TRUE ) + if( it->second == TRUE ) { - ( *it )->setChecked( FALSE ); + it->second = FALSE; activatedWriteablePort( *it ); } } } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } -void midiTabWidget::readablePortsChanged( void ) +void instrumentMidiIO::readablePortsChanged( void ) { // first save all selected ports QStringList selected_ports; - QList actions = m_readablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_readablePorts.begin(); + it != m_readablePorts.end(); ++it ) { - if( ( *it )->isChecked() == TRUE ) + if( it->second == TRUE ) { - selected_ports.push_back( ( *it )->text() ); + selected_ports.push_back( it->first ); } } - m_readablePorts->clear(); - const QStringList & rp = engine::getMixer()->getMIDIClient()-> + m_readablePorts.clear(); + const QStringList & wp = engine::getMixer()->getMIDIClient()-> readablePorts(); // now insert new ports and restore selections - for( QStringList::const_iterator it = rp.begin(); it != rp.end(); ++it ) + for( QStringList::const_iterator it = wp.begin(); it != wp.end(); ++it ) { - QAction * item = m_readablePorts->addAction( *it ); - item->setCheckable( TRUE ); - if( selected_ports.indexOf( *it ) != -1 ) - { - item->setChecked( TRUE ); - } + m_readablePorts.push_back( qMakePair( *it, + selected_ports.indexOf( *it ) != -1 ) ); } + emit dataChanged(); } -void midiTabWidget::writeablePortsChanged( void ) +void instrumentMidiIO::writeablePortsChanged( void ) { // first save all selected ports QStringList selected_ports; - QList actions = m_writeablePorts->actions(); - for( QList::iterator it = actions.begin(); - it != actions.end(); ++it ) + for( midiPortMap::iterator it = m_writeablePorts.begin(); + it != m_writeablePorts.end(); ++it ) { - if( ( *it )->isChecked() == TRUE ) + if( it->second == TRUE ) { - selected_ports.push_back( ( *it )->text() ); + selected_ports.push_back( it->first ); } } - m_writeablePorts->clear(); + m_writeablePorts.clear(); const QStringList & wp = engine::getMixer()->getMIDIClient()-> writeablePorts(); // now insert new ports and restore selections for( QStringList::const_iterator it = wp.begin(); it != wp.end(); ++it ) { - QAction * item = m_writeablePorts->addAction( *it ); - item->setCheckable( TRUE ); - if( selected_ports.indexOf( *it ) != -1 ) - { - item->setChecked( TRUE ); - } + m_writeablePorts.push_back( qMakePair( *it, + selected_ports.indexOf( *it ) != -1 ) ); } + emit dataChanged(); } -void midiTabWidget::activatedReadablePort( QAction * _item ) +void instrumentMidiIO::activatedReadablePort( + const descriptiveMidiPort & _port ) { // make sure, MIDI-port is configured for input - if( _item->isChecked() == TRUE && + if( _port.second == TRUE && m_midiPort->mode() != midiPort::INPUT && m_midiPort->mode() != midiPort::DUPLEX ) { m_receiveEnabledModel.setValue( TRUE ); } engine::getMixer()->getMIDIClient()->subscribeReadablePort( m_midiPort, - _item->text(), !_item->isChecked() ); + _port.first, !_port.second ); } -void midiTabWidget::activatedWriteablePort( QAction * _item ) +void instrumentMidiIO::activatedWriteablePort( + const descriptiveMidiPort & _port ) { // make sure, MIDI-port is configured for output - if( _item->isChecked() == TRUE && + if( _port.second == TRUE && m_midiPort->mode() != midiPort::OUTPUT && m_midiPort->mode() != midiPort::DUPLEX ) { m_sendEnabledModel.setValue( TRUE ); } engine::getMixer()->getMIDIClient()->subscribeWriteablePort( m_midiPort, - _item->text(), !_item->isChecked() ); + _port.first, !_port.second ); } diff --git a/src/core/instrument_sound_shaping.cpp b/src/core/instrument_sound_shaping.cpp index 803f4a185f..0f386ba200 100644 --- a/src/core/instrument_sound_shaping.cpp +++ b/src/core/instrument_sound_shaping.cpp @@ -1,8 +1,7 @@ #ifndef SINGLE_SOURCE_COMPILE /* - * envelope_tab_widget.cpp - widget for use in envelope/lfo/filter-tab of - * instrument-track-window + * instrument_sound_shaping.cpp - class instrumentSoundShaping * * Copyright (c) 2004-2008 Tobias Doerffel * @@ -30,29 +29,14 @@ #include "instrument_sound_shaping.h" -#include "combobox.h" #include "embed.h" #include "engine.h" #include "envelope_and_lfo_parameters.h" -#include "group_box.h" -#include "gui_templates.h" #include "instrument_track.h" -#include "knob.h" #include "note_play_handle.h" -#include "tab_widget.h" -const int TARGETS_TABWIDGET_X = 4; -const int TARGETS_TABWIDGET_Y = 5; -const int TARGETS_TABWIDGET_WIDTH = 238; -const int TARGETS_TABWIDGET_HEIGTH = 175; - -const int FILTER_GROUPBOX_X = TARGETS_TABWIDGET_X; -const int FILTER_GROUPBOX_Y = TARGETS_TABWIDGET_Y+TARGETS_TABWIDGET_HEIGTH+5; -const int FILTER_GROUPBOX_WIDTH = TARGETS_TABWIDGET_WIDTH; -const int FILTER_GROUPBOX_HEIGHT = 245-FILTER_GROUPBOX_Y; - const float CUT_FREQ_MULTIPLIER = 6000.0f; const float RES_MULTIPLIER = 2.0f; const float RES_PRECISION = 1000.0f; @@ -60,149 +44,75 @@ const float RES_PRECISION = 1000.0f; // names for env- and lfo-targets - first is name being displayed to user // and second one is used internally, e.g. for saving/restoring settings -static const QString targetNames[envelopeTabWidget::TARGET_COUNT][2] = +const QString __targetNames[instrumentSoundShaping::NumTargets][2] = { - { envelopeTabWidget::tr( "VOLUME" ), "vol" }, -/* envelopeTabWidget::tr( "Pan" ), - envelopeTabWidget::tr( "Pitch" ),*/ - { envelopeTabWidget::tr( "CUTOFF" ), "cut" }, - { envelopeTabWidget::tr( "Q/RESO" ), "res" } + { instrumentSoundShaping::tr( "VOLUME" ), "vol" }, +/* instrumentSoundShaping::tr( "Pan" ), + instrumentSoundShaping::tr( "Pitch" ),*/ + { instrumentSoundShaping::tr( "CUTOFF" ), "cut" }, + { instrumentSoundShaping::tr( "Q/RESO" ), "res" } } ; -envelopeTabWidget::envelopeTabWidget( instrumentTrack * _instrument_track ) : - QWidget( _instrument_track->tabWidgetParent() ), +instrumentSoundShaping::instrumentSoundShaping( + instrumentTrack * _instrument_track ) : + model( _instrument_track ), m_instrumentTrack( _instrument_track ), - m_filterEnabledModel( new boolModel( FALSE /* this */ ) ), - m_filterModel( new comboBoxModel( /* this */ ) ), - m_filterCutModel( new floatModel( /* this */ ) ), - m_filterResModel( new floatModel( /* this */ ) ) + m_filterEnabledModel( FALSE, this ), + m_filterModel( this ), + m_filterCutModel( 16000.0, 0.0, 14000.0, 1.0, this ), + m_filterResModel( 0.5, basicFilters<>::minQ(), 10.0, 0.01, this ) { - m_targetsTabWidget = new tabWidget( tr( "TARGET" ), this ); - m_targetsTabWidget->setGeometry( TARGETS_TABWIDGET_X, - TARGETS_TABWIDGET_Y, - TARGETS_TABWIDGET_WIDTH, - TARGETS_TABWIDGET_HEIGTH ); - m_targetsTabWidget->setWhatsThis( - tr( "These tabs contain envelopes. They're very important for " - "modifying a sound, for not saying that they're almost " - "always neccessary for substractive synthesis. For " - "example if you have a volume-envelope, you can set " - "when the sound should have which volume-level. " - "Maybe you want to create some soft strings. Then your " - "sound has to fade in and out very softly. This can be " - "done by setting a large attack- and release-time. " - "It's the same for other envelope-targets like " - "panning, cutoff-frequency of used filter and so on. " - "Just monkey around with it! You can really make cool " - "sounds out of a saw-wave with just some " - "envelopes...!" ) ); - - for( int i = 0; i < TARGET_COUNT; ++i ) + for( int i = 0; i < NumTargets; ++i ) { float value_for_zero_amount = 0.0; - if( i == VOLUME ) + if( i == Volume ) { value_for_zero_amount = 1.0; } - m_envLFOWidgets[i] = new envelopeAndLFOWidget( - value_for_zero_amount, - m_targetsTabWidget, - _instrument_track ); - m_targetsTabWidget->addTab( m_envLFOWidgets[i], - tr( targetNames[i][0] - .toAscii().constData() ) ); + m_envLFOParameters[i] = new envelopeAndLFOParameters( + value_for_zero_amount, + _instrument_track, + this ); } + m_filterEnabledModel.setTrack( _instrument_track ); - m_filterEnabledModel->setTrack( _instrument_track ); - m_filterGroupBox = new groupBox( tr( "FILTER" ), this ); - m_filterGroupBox->setModel( m_filterEnabledModel ); - m_filterGroupBox->setGeometry( FILTER_GROUPBOX_X, FILTER_GROUPBOX_Y, - FILTER_GROUPBOX_WIDTH, - FILTER_GROUPBOX_HEIGHT ); - - - m_filterModel->addItem( tr( "LowPass" ), new QPixmap( + m_filterModel.addItem( tr( "LowPass" ), new QPixmap( embed::getIconPixmap( "filter_lp" ) ) ); - m_filterModel->addItem( tr( "HiPass" ), new QPixmap( + m_filterModel.addItem( tr( "HiPass" ), new QPixmap( embed::getIconPixmap( "filter_hp" ) ) ); - m_filterModel->addItem( tr( "BandPass csg" ), new QPixmap( + m_filterModel.addItem( tr( "BandPass csg" ), new QPixmap( embed::getIconPixmap( "filter_bp" ) ) ); - m_filterModel->addItem( tr( "BandPass czpg" ), new QPixmap( + m_filterModel.addItem( tr( "BandPass czpg" ), new QPixmap( embed::getIconPixmap( "filter_bp" ) ) ); - m_filterModel->addItem( tr( "Notch" ), new QPixmap( + m_filterModel.addItem( tr( "Notch" ), new QPixmap( embed::getIconPixmap( "filter_notch" ) ) ); - m_filterModel->addItem( tr( "Allpass" ), new QPixmap( + m_filterModel.addItem( tr( "Allpass" ), new QPixmap( embed::getIconPixmap( "filter_ap" ) ) ); - m_filterModel->addItem( tr( "Moog" ), new QPixmap( + m_filterModel.addItem( tr( "Moog" ), new QPixmap( embed::getIconPixmap( "filter_lp" ) ) ); - m_filterModel->addItem( tr( "2x LowPass" ), new QPixmap( + m_filterModel.addItem( tr( "2x LowPass" ), new QPixmap( embed::getIconPixmap( "filter_2lp" ) ) ); - m_filterModel->setTrack( _instrument_track ); - m_filterComboBox = new comboBox( m_filterGroupBox, tr( "Filter type" ) ); - m_filterComboBox->setModel( m_filterModel ); - m_filterComboBox->setGeometry( 14, 22, 120, 22 ); - m_filterComboBox->setFont( pointSize<8>( m_filterComboBox->font() ) ); - - m_filterComboBox->setWhatsThis( - tr( "Here you can select the built-in filter you want to use " - "for this instrument-track. Filters are very important " - "for changing the characteristics of a sound." ) ); - - - m_filterCutModel->setTrack( _instrument_track ); - m_filterCutModel->setRange( 0.0, 14000.0, 1.0 ); - m_filterCutModel->setInitValue( 16000.0 ); - - m_filterCutKnob = new knob( knobBright_26, m_filterGroupBox, - tr( "cutoff-frequency" ) ); - m_filterCutKnob->setModel( m_filterCutModel ); - m_filterCutKnob->setLabel( tr( "CUTOFF" ) ); - m_filterCutKnob->move( 140, 18 ); - m_filterCutKnob->setHintText( tr( "cutoff-frequency:" ) + " ", " " + - tr( "Hz" ) ); - m_filterCutKnob->setWhatsThis( - tr( "Use this knob for setting the cutoff-frequency for the " - "selected filter. The cutoff-frequency specifies the " - "frequency for cutting the signal by a filter. For " - "example a lowpass-filter cuts all frequencies above " - "the cutoff-frequency. A highpass-filter cuts all " - "frequencies below cutoff-frequency and so on..." ) ); - - - - m_filterResModel->setTrack( _instrument_track ); - m_filterResModel->setRange( basicFilters<>::minQ(), 10.0, 0.01 ); - m_filterResModel->setInitValue( 0.5 ); - - m_filterResKnob = new knob( knobBright_26, m_filterGroupBox, - tr( "Q/Resonance" ) ); - m_filterResKnob->setModel( m_filterResModel ); - m_filterResKnob->setLabel( tr( "Q/RESO" ) ); - m_filterResKnob->move( 190, 18 ); - m_filterResKnob->setHintText( tr( "Q/Resonance:" ) + " ", "" ); - m_filterResKnob->setWhatsThis( - tr( "Use this knob for setting Q/Resonance for the selected " - "filter. Q/Resonance tells the filter, how much it " - "should amplify frequencies near Cutoff-frequency." ) ); + m_filterModel.setTrack( _instrument_track ); + m_filterCutModel.setTrack( _instrument_track ); + m_filterResModel.setTrack( _instrument_track ); } -envelopeTabWidget::~envelopeTabWidget() +instrumentSoundShaping::~instrumentSoundShaping() { - delete m_targetsTabWidget; } -float FASTCALL envelopeTabWidget::volumeLevel( notePlayHandle * _n, +float instrumentSoundShaping::volumeLevel( notePlayHandle * _n, const f_cnt_t _frame ) { f_cnt_t release_begin = _frame - _n->releaseFramesDone() + @@ -214,7 +124,7 @@ float FASTCALL envelopeTabWidget::volumeLevel( notePlayHandle * _n, } float volume_level; - m_envLFOWidgets[VOLUME]->fillLevel( &volume_level, _frame, + m_envLFOParameters[Volume]->fillLevel( &volume_level, _frame, release_begin, 1 ); return( volume_level ); @@ -223,7 +133,7 @@ float FASTCALL envelopeTabWidget::volumeLevel( notePlayHandle * _n, -void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, +void instrumentSoundShaping::processAudioBuffer( sampleFrame * _ab, const fpp_t _frames, notePlayHandle * _n ) { @@ -244,7 +154,7 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, // only use filter, if it is really needed - if( m_filterEnabledModel->value() ) + if( m_filterEnabledModel.value() ) { int old_filter_cut = 0; int old_filter_res = 0; @@ -254,33 +164,34 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, _n->m_filter = new basicFilters<>( engine::getMixer()->sampleRate() ); } - _n->m_filter->setFilterType( m_filterComboBox->value() ); + _n->m_filter->setFilterType( m_filterModel.value() ); float * cut_buf = NULL; float * res_buf = NULL; - if( m_envLFOWidgets[CUT]->used() ) + if( m_envLFOParameters[Cut]->used() ) { cut_buf = new float[_frames]; - m_envLFOWidgets[CUT]->fillLevel( cut_buf, total_frames, + m_envLFOParameters[Cut]->fillLevel( cut_buf, total_frames, release_begin, _frames ); } - if( m_envLFOWidgets[RES]->used() ) + if( m_envLFOParameters[Resonance]->used() ) { res_buf = new float[_frames]; - m_envLFOWidgets[RES]->fillLevel( res_buf, total_frames, - release_begin, _frames ); + m_envLFOParameters[Resonance]->fillLevel( res_buf, + total_frames, release_begin, + _frames ); } - if( m_envLFOWidgets[CUT]->used() && - m_envLFOWidgets[RES]->used() ) + if( m_envLFOParameters[Cut]->used() && + m_envLFOParameters[Resonance]->used() ) { for( fpp_t frame = 0; frame < _frames; ++frame ) { - float new_cut_val = envelopeAndLFOWidget::expKnobVal( cut_buf[frame] ) * CUT_FREQ_MULTIPLIER + - m_filterCutKnob->value(); + float new_cut_val = envelopeAndLFOParameters::expKnobVal( cut_buf[frame] ) * CUT_FREQ_MULTIPLIER + + m_filterCutModel.value(); - float new_res_val = m_filterResKnob->value() + RES_MULTIPLIER * + float new_res_val = m_filterResModel.value() + RES_MULTIPLIER * res_buf[frame]; if( static_cast( new_cut_val ) != old_filter_cut || @@ -297,16 +208,16 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, } } } - else if( m_envLFOWidgets[CUT]->used() ) + else if( m_envLFOParameters[Cut]->used() ) { for( fpp_t frame = 0; frame < _frames; ++frame ) { - float new_cut_val = envelopeAndLFOWidget::expKnobVal( cut_buf[frame] ) * CUT_FREQ_MULTIPLIER + - m_filterCutKnob->value(); + float new_cut_val = envelopeAndLFOParameters::expKnobVal( cut_buf[frame] ) * CUT_FREQ_MULTIPLIER + + m_filterCutModel.value(); if( static_cast( new_cut_val ) != old_filter_cut ) { - _n->m_filter->calcFilterCoeffs( new_cut_val, m_filterResKnob->value() ); + _n->m_filter->calcFilterCoeffs( new_cut_val, m_filterResModel.value() ); old_filter_cut = static_cast( new_cut_val ); } @@ -316,16 +227,16 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, } } } - else if( m_envLFOWidgets[RES]->used() ) + else if( m_envLFOParameters[Resonance]->used() ) { for( fpp_t frame = 0; frame < _frames; ++frame ) { - float new_res_val = m_filterResKnob->value() + RES_MULTIPLIER * + float new_res_val = m_filterResModel.value() + RES_MULTIPLIER * res_buf[frame]; if( static_cast( new_res_val*RES_PRECISION ) != old_filter_res ) { - _n->m_filter->calcFilterCoeffs( m_filterCutKnob->value(), new_res_val ); + _n->m_filter->calcFilterCoeffs( m_filterCutModel.value(), new_res_val ); old_filter_res = static_cast( new_res_val*RES_PRECISION ); } @@ -337,7 +248,7 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, } else { - _n->m_filter->calcFilterCoeffs( m_filterCutKnob->value(), m_filterResKnob->value() ); + _n->m_filter->calcFilterCoeffs( m_filterCutModel.value(), m_filterResModel.value() ); for( fpp_t frame = 0; frame < _frames; ++frame ) { @@ -352,10 +263,10 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, delete[] res_buf; } - if( m_envLFOWidgets[VOLUME]->used() ) + if( m_envLFOParameters[Volume]->used() ) { float * vol_buf = new float[_frames]; - m_envLFOWidgets[VOLUME]->fillLevel( vol_buf, total_frames, + m_envLFOParameters[Volume]->fillLevel( vol_buf, total_frames, release_begin, _frames ); for( fpp_t frame = 0; frame < _frames; ++frame ) @@ -371,7 +282,7 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, delete[] vol_buf; } -/* else if( m_envLFOWidgets[VOLUME]->used() == FALSE && m_envLFOWidgets[PANNING]->used() ) +/* else if( m_envLFOParameters[Volume]->used() == FALSE && m_envLFOParameters[PANNING]->used() ) { // only use panning-envelope... for( fpp_t frame = 0; frame < _frames; ++frame ) @@ -389,18 +300,18 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, -f_cnt_t envelopeTabWidget::envFrames( const bool _only_vol ) +f_cnt_t instrumentSoundShaping::envFrames( const bool _only_vol ) const { - f_cnt_t ret_val = m_envLFOWidgets[VOLUME]->m_pahdFrames; + f_cnt_t ret_val = m_envLFOParameters[Volume]->PAHD_Frames(); if( _only_vol == FALSE ) { - for( int i = VOLUME+1; i < TARGET_COUNT; ++i ) + for( int i = Volume+1; i < NumTargets; ++i ) { - if( m_envLFOWidgets[i]->used() && - m_envLFOWidgets[i]->m_pahdFrames > ret_val ) + if( m_envLFOParameters[i]->used() && + m_envLFOParameters[i]->PAHD_Frames() > ret_val ) { - ret_val = m_envLFOWidgets[i]->m_pahdFrames; + ret_val = m_envLFOParameters[i]->PAHD_Frames(); } } } @@ -410,10 +321,10 @@ f_cnt_t envelopeTabWidget::envFrames( const bool _only_vol ) -f_cnt_t envelopeTabWidget::releaseFrames( const bool _only_vol ) +f_cnt_t instrumentSoundShaping::releaseFrames( const bool _only_vol ) const { - f_cnt_t ret_val = m_envLFOWidgets[VOLUME]->used() ? - m_envLFOWidgets[VOLUME]->m_rFrames : 0; + f_cnt_t ret_val = m_envLFOParameters[Volume]->used() ? + m_envLFOParameters[Volume]->releaseFrames() : 0; if( m_instrumentTrack->getInstrument()->desiredReleaseFrames() > ret_val ) { @@ -421,14 +332,15 @@ f_cnt_t envelopeTabWidget::releaseFrames( const bool _only_vol ) desiredReleaseFrames(); } - if( m_envLFOWidgets[VOLUME]->used() == FALSE ) + if( m_envLFOParameters[Volume]->used() == FALSE ) { - for( int i = VOLUME+1; i < TARGET_COUNT; ++i ) + for( int i = Volume+1; i < NumTargets; ++i ) { - if( m_envLFOWidgets[i]->used() && - m_envLFOWidgets[i]->m_rFrames > ret_val ) + if( m_envLFOParameters[i]->used() && + m_envLFOParameters[i]->releaseFrames() > + ret_val ) { - ret_val = m_envLFOWidgets[i]->m_rFrames; + ret_val = m_envLFOParameters[i]->releaseFrames(); } } } @@ -438,43 +350,44 @@ f_cnt_t envelopeTabWidget::releaseFrames( const bool _only_vol ) -void envelopeTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void instrumentSoundShaping::saveSettings( QDomDocument & _doc, QDomElement & _this ) { - m_filterModel->saveSettings( _doc, _this, "ftype" ); - m_filterCutModel->saveSettings( _doc, _this, "fcut" ); - m_filterResModel->saveSettings( _doc, _this, "fres" ); - m_filterEnabledModel->saveSettings( _doc, _this, "fwet" ); + m_filterModel.saveSettings( _doc, _this, "ftype" ); + m_filterCutModel.saveSettings( _doc, _this, "fcut" ); + m_filterResModel.saveSettings( _doc, _this, "fres" ); + m_filterEnabledModel.saveSettings( _doc, _this, "fwet" ); - for( int i = 0; i < TARGET_COUNT; ++i ) + for( int i = 0; i < NumTargets; ++i ) { - m_envLFOWidgets[i]->saveState( _doc, _this ).setTagName( - m_envLFOWidgets[i]->nodeName() + - QString( targetNames[i][1] ).toLower() ); + m_envLFOParameters[i]->saveState( _doc, _this ).setTagName( + m_envLFOParameters[i]->nodeName() + + QString( __targetNames[i][1] ).toLower() ); } } -void envelopeTabWidget::loadSettings( const QDomElement & _this ) +void instrumentSoundShaping::loadSettings( const QDomElement & _this ) { - m_filterModel->loadSettings( _this, "ftype" ); - m_filterCutModel->loadSettings( _this, "fcut" ); - m_filterResModel->loadSettings( _this, "fres" ); - m_filterEnabledModel->loadSettings( _this, "fwet" ); + m_filterModel.loadSettings( _this, "ftype" ); + m_filterCutModel.loadSettings( _this, "fcut" ); + m_filterResModel.loadSettings( _this, "fres" ); + m_filterEnabledModel.loadSettings( _this, "fwet" ); QDomNode node = _this.firstChild(); while( !node.isNull() ) { if( node.isElement() ) { - for( int i = 0; i < TARGET_COUNT; ++i ) + for( int i = 0; i < NumTargets; ++i ) { if( node.nodeName() == - m_envLFOWidgets[i]->nodeName() + - QString( targetNames[i][1] ).toLower() ) + m_envLFOParameters[i]->nodeName() + + QString( __targetNames[i][1] ). + toLower() ) { - m_envLFOWidgets[i]->restoreState( + m_envLFOParameters[i]->restoreState( node.toElement() ); } } @@ -486,9 +399,7 @@ void envelopeTabWidget::loadSettings( const QDomElement & _this ) -#include "instrument_sound_shaping.moc" - - +//#include "instrument_sound_shaping.moc" /* diff --git a/src/core/main.cpp b/src/core/main.cpp index c9211f3920..449b8c6654 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -41,7 +41,7 @@ #include "engine.h" #include "config_mgr.h" #include "export_project_dialog.h" -#include "song_editor.h" +#include "song.h" #include "gui_templates.h" #include "automatable_model_templates.h" @@ -200,11 +200,11 @@ int main( int argc, char * * argv ) // we try to load given file if( file_to_load != "" ) { - engine::getSongEditor()->loadProject( file_to_load ); + engine::getSong()->loadProject( file_to_load ); } else { - engine::getSongEditor()->createNewProject(); + engine::getSong()->createNewProject(); } // MDI-mode? diff --git a/src/core/main_window.cpp b/src/core/main_window.cpp index 34d9e98d35..8b1248fa2b 100644 --- a/src/core/main_window.cpp +++ b/src/core/main_window.cpp @@ -48,6 +48,7 @@ #include "bb_editor.h" #include "song_editor.h" +#include "song.h" #include "piano_roll.h" #include "embed.h" #include "engine.h" @@ -77,8 +78,7 @@ mainWindow::mainWindow( void ) : m_workspace( NULL ), m_templatesMenu( NULL ), m_recentlyOpenedProjectsMenu( NULL ), - m_toolsMenu( NULL ), - m_modified( FALSE ) + m_toolsMenu( NULL ) { setAttribute( Qt::WA_DeleteOnClose ); @@ -514,24 +514,23 @@ void mainWindow::addSpacingToToolBar( int _size ) -void mainWindow::resetWindowTitle( bool _modified ) +void mainWindow::resetWindowTitle( void ) { QString title = ""; - if( engine::getSongEditor()->projectFileName() != "" ) + if( engine::getSong()->projectFileName() != "" ) { - title = QFileInfo( engine::getSongEditor()->projectFileName() + title = QFileInfo( engine::getSong()->projectFileName() ).completeBaseName(); } if( title == "" ) { title = tr( "Untitled" ); } - if( _modified ) + if( engine::getSong()->isModified() ) { title += '*'; } setWindowTitle( title + " - " + tr( "LMMS %1" ).arg( VERSION ) ); - m_modified = _modified; } @@ -539,7 +538,7 @@ void mainWindow::resetWindowTitle( bool _modified ) bool mainWindow::mayChangeProject( void ) { - if( !m_modified ) + if( !engine::getSong()->isModified() ) { return( TRUE ); } @@ -626,7 +625,7 @@ void mainWindow::createNewProject( void ) { if( mayChangeProject() ) { - engine::getSongEditor()->createNewProject(); + engine::getSong()->createNewProject(); } } @@ -641,7 +640,7 @@ void mainWindow::createNewProjectFromTemplate( QAction * _idx ) >= m_custom_templates_count ? configManager::inst()->factoryProjectsDir() : configManager::inst()->userProjectsDir(); - engine::getSongEditor()->createNewProjectFromTemplate( + engine::getSong()->createNewProjectFromTemplate( dir_base + "templates/" + _idx->text() + ".mpt" ); } } @@ -661,7 +660,7 @@ void mainWindow::openProject( void ) if( ofd.exec () == QDialog::Accepted && !ofd.selectedFiles().isEmpty() ) { - engine::getSongEditor()->loadProject( + engine::getSong()->loadProject( ofd.selectedFiles()[0] ); } } @@ -686,7 +685,7 @@ void mainWindow::updateRecentlyOpenedProjectsMenu( void ) void mainWindow::openRecentlyOpenedProject( QAction * _action ) { const QString & f = _action->text(); - engine::getSongEditor()->loadProject( f ); + engine::getSong()->loadProject( f ); configManager::inst()->addRecentlyOpenedProject( f ); } @@ -695,13 +694,13 @@ void mainWindow::openRecentlyOpenedProject( QAction * _action ) bool mainWindow::saveProject( void ) { - if( engine::getSongEditor()->projectFileName() == "" ) + if( engine::getSong()->projectFileName() == "" ) { return( saveProjectAs() ); } else { - engine::getSongEditor()->saveProject(); + engine::getSong()->saveProject(); } return( TRUE ); } @@ -716,7 +715,7 @@ bool mainWindow::saveProjectAs( void ) "MultiMedia Project Template (*.mpt)" ) ); sfd.setAcceptMode( QFileDialog::AcceptSave ); sfd.setFileMode( QFileDialog::AnyFile ); - QString f = engine::getSongEditor()->projectFileName(); + QString f = engine::getSong()->projectFileName(); if( f != "" ) { sfd.selectFile( QFileInfo( f ).fileName() ); @@ -730,7 +729,7 @@ bool mainWindow::saveProjectAs( void ) if( sfd.exec () == QFileDialog::Accepted && !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" ) { - engine::getSongEditor()->saveProjectAs( + engine::getSong()->saveProjectAs( sfd.selectedFiles()[0] ); return( TRUE ); } diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index c11940acf6..9b421c2045 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -29,7 +29,7 @@ #include "mixer.h" #include "play_handle.h" -#include "song_editor.h" +#include "song.h" #include "templates.h" #include "envelope_and_lfo_parameters.h" #include "debug.h" @@ -177,7 +177,7 @@ void mixer::stopProcessing( void ) bool mixer::criticalXRuns( void ) const { return( ( m_cpuLoad >= 99 && - engine::getSongEditor()->realTimeTask() == TRUE ) ); + engine::getSong()->realTimeTask() == TRUE ) ); } @@ -230,11 +230,11 @@ void mixer::setClipScaling( bool _state ) const surroundSampleFrame * mixer::renderNextBuffer( void ) { microTimer timer; - static songEditor::playPos last_metro_pos = -1; + static song::playPos last_metro_pos = -1; - songEditor::playPos p = engine::getSongEditor()->getPlayPos( - songEditor::PLAY_PATTERN ); - if( engine::getSongEditor()->playMode() == songEditor::PLAY_PATTERN && + song::playPos p = engine::getSong()->getPlayPos( + song::Mode_PlayPattern ); + if( engine::getSong()->playMode() == song::Mode_PlayPattern && engine::getPianoRoll()->isRecording() == TRUE && p != last_metro_pos && p.getTact64th() % 16 == 0 ) { @@ -288,7 +288,7 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) //printf("---------------------------next period\n"); // if( criticalXRuns() == FALSE ) { - engine::getSongEditor()->processNextBuffer(); + engine::getSong()->processNextBuffer(); lockPlayHandles(); int idx = 0; @@ -382,7 +382,7 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) emit nextAudioBuffer(); // and trigger LFOs - envelopeAndLFOWidget::triggerLFO(); + envelopeAndLFOParameters::triggerLFO(); const float new_cpu_load = timer.elapsed() / 10000.0f * sampleRate() / m_framesPerPeriod; diff --git a/src/core/mv_base.cpp b/src/core/mv_base.cpp index 3eb7ded89e..f9089d0730 100644 --- a/src/core/mv_base.cpp +++ b/src/core/mv_base.cpp @@ -35,6 +35,7 @@ void modelView::setModel( model * _model, bool _old_model_valid ) QWidget * w = dynamic_cast( this ); assert( w != NULL ); +//printf("w: %x m_model:%x _model:%x\n", w, m_model, _model); if( _old_model_valid && m_model != NULL ) { if( m_model->defaultConstructed() ) @@ -46,7 +47,6 @@ void modelView::setModel( model * _model, bool _old_model_valid ) m_model->disconnect( w ); } } - m_model = _model; QObject::connect( _model, SIGNAL( dataChanged() ), w, SLOT( update() ) ); diff --git a/src/core/name_label.cpp b/src/core/name_label.cpp index c3d313dce0..c3f4a6296c 100644 --- a/src/core/name_label.cpp +++ b/src/core/name_label.cpp @@ -4,7 +4,7 @@ * name_label.cpp - implementation of class nameLabel, a label which * is renamable by double-clicking it * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -148,7 +148,6 @@ void nameLabel::rename( void ) { setText( txt ); emit nameChanged( txt ); - emit nameChanged(); } } @@ -222,13 +221,14 @@ void nameLabel::paintEvent( QPaintEvent * ) text() ); p.setPen( QColor( 0, 224, 0 ) ); - bbTrack * bbt = bbTrack::findBBTrack( - engine::getBBEditor()->currentBB() ); +#warning: TODO +/* bbTrack * bbt = bbTrack::findBBTrack( + engine::getBBTrackContainer()->currentBB() ); if( bbt != NULL && bbt->getTrackSettingsWidget() == dynamic_cast( parentWidget() ) ) { p.setPen( QColor( 255, 255, 255 ) ); - } + }*/ p.drawText( x, height() / 2 + p.fontMetrics().height() / 2 - 4, text() ); diff --git a/src/core/note_play_handle.cpp b/src/core/note_play_handle.cpp index af3ca2e42d..826dc77820 100644 --- a/src/core/note_play_handle.cpp +++ b/src/core/note_play_handle.cpp @@ -4,7 +4,7 @@ * note_play_handle.cpp - implementation of class notePlayHandle, part of * play-engine * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -33,7 +33,7 @@ #include "instrument_sound_shaping.h" #include "instrument_track.h" #include "midi_port.h" -#include "song_editor.h" +#include "song.h" inline notePlayHandle::baseDetuning::baseDetuning( @@ -85,7 +85,7 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it, #if SINGERBOT_SUPPORT m_patternIndex( 0 ), #endif - m_orig_bpm( engine::getSongEditor()->getTempo() ) + m_orig_bpm( engine::getSong()->getTempo() ) { if( m_baseNote ) { @@ -306,7 +306,7 @@ void notePlayHandle::noteOff( const f_cnt_t _s ) // then set some variables indicating release-state m_framesBeforeRelease = _s; m_releaseFramesToDo = tMax( 0, // 10, - m_instrumentTrack->m_envWidget->releaseFrames() ); + m_instrumentTrack->m_soundShaping.releaseFrames() ); // send MIDI-note-off-event m_instrumentTrack->processOutEvent( midiEvent( NOTE_OFF, m_instrumentTrack->m_midiPort->outputChannel(), @@ -322,7 +322,7 @@ void notePlayHandle::noteOff( const f_cnt_t _s ) f_cnt_t notePlayHandle::actualReleaseFramesToDo( void ) const { - return( m_instrumentTrack->m_envWidget->releaseFrames( + return( m_instrumentTrack->m_soundShaping.releaseFrames( arpBaseNote() ) ); } @@ -344,7 +344,7 @@ void notePlayHandle::setFrames( const f_cnt_t _frames ) float notePlayHandle::volumeLevel( const f_cnt_t _frame ) { - return( m_instrumentTrack->m_envWidget->volumeLevel( this, _frame ) ); + return( m_instrumentTrack->m_soundShaping.volumeLevel( this, _frame ) ); } @@ -441,7 +441,7 @@ void notePlayHandle::updateFrequency( void ) const int base_octave = m_instrumentTrack->baseNoteModel()->value() / NOTES_PER_OCTAVE; const float pitch = (float)( tone() - base_tone + - engine::getSongEditor()->masterPitch() ) / 12.0f + + engine::getSong()->masterPitch() ) / 12.0f + (float)( octave() - base_octave ) + m_base_detuning->value() / 12.0f; m_frequency = BASE_FREQ * powf( 2.0f, pitch ); diff --git a/src/core/piano_roll.cpp b/src/core/piano_roll.cpp index da0e136d6a..727fffee00 100644 --- a/src/core/piano_roll.cpp +++ b/src/core/piano_roll.cpp @@ -4,7 +4,7 @@ * piano_roll.cpp - implementation of piano-roll which is used for actual * writing of melodies * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -61,6 +61,7 @@ #include "pattern.h" #include "piano_widget.h" #include "pixmap_button.h" +#include "song.h" #include "song_editor.h" #include "templates.h" #include "text_float.h" @@ -189,8 +190,8 @@ pianoRoll::pianoRoll( void ) : // add time-line m_timeLine = new timeLine( WHITE_KEY_WIDTH, 32, m_ppt, - engine::getSongEditor()->getPlayPos( - songEditor::PLAY_PATTERN ), + engine::getSong()->getPlayPos( + song::Mode_PlayPattern ), m_currentPosition, this ); connect( this, SIGNAL( positionChanged( const midiTime & ) ), m_timeLine, SLOT( updatePosition( const midiTime & ) ) ); @@ -641,8 +642,9 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke ) { if( validPattern() ) { - m_pattern->getInstrumentTrack()->getPianoWidget() - ->keyPressEvent( _ke ); + // TODO: move this to instrumentTrack-class +/* m_pattern->getInstrumentTrack()->getPianoWidget() + ->keyPressEvent( _ke );*/ } switch( _ke->key() ) { @@ -768,7 +770,7 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke ) break; case Qt::Key_Space: - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { stop(); } @@ -806,8 +808,8 @@ void pianoRoll::keyReleaseEvent( QKeyEvent * _ke ) { if( validPattern() ) { - m_pattern->getInstrumentTrack()->getPianoWidget() - ->keyReleaseEvent( _ke ); +/* m_pattern->getInstrumentTrack()->getPianoWidget() + ->keyReleaseEvent( _ke );*/ } switch( _ke->key() ) { @@ -934,7 +936,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me ) if( it == notes.end() ) { m_pattern->setType( - pattern::MELODY_PATTERN ); + pattern::MelodyPattern ); // then set new note midiTime note_pos( pos_tact_64th ); @@ -991,7 +993,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me ) QApplication::setOverrideCursor( c ); } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( ( _me->button() == Qt::RightButton && m_editMode == DRAW ) || @@ -1009,9 +1011,9 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me ) else { ( *it )->setLength( 0 ); - m_pattern->update(); + m_pattern->dataChanged(); } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } else if( _me->button() == Qt::LeftButton && @@ -1050,7 +1052,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me ) m_action = MOVE_SELECTION; play_note = FALSE; - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( _me->button() == Qt::RightButton && m_editMode == MOVE ) @@ -1066,7 +1068,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me ) // was there an action where should be played the note? if( play_note == TRUE && m_recording == FALSE && - engine::getSongEditor()->playing() == FALSE ) + engine::getSong()->playing() == FALSE ) { m_lastKey = key_num; m_pattern->getInstrumentTrack()->processInEvent( @@ -1144,7 +1146,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) m_action != SELECT_NOTES && m_action != MOVE_SELECTION && m_recording == FALSE && - engine::getSongEditor()->playing() == FALSE ) + engine::getSong()->playing() == FALSE ) { m_lastKey = key_num; m_pattern->getInstrumentTrack()->processInEvent( @@ -1171,7 +1173,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) MIN_VOLUME, MAX_VOLUME ); m_currentNote->setVolume( vol ); - m_pattern->update(); + m_pattern->dataChanged(); m_pattern->getInstrumentTrack()->processInEvent( midiEvent( KEY_PRESSURE, 0, key_num, vol * 127 / 100 ), @@ -1219,10 +1221,10 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) tact_64th_diff ) ); m_currentNote->quantizeLength( quantization() ); m_lenOfNewNotes = m_currentNote->length(); - m_pattern->update(); + m_pattern->dataChanged(); } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } else if( _me->buttons() == Qt::NoButton && m_editMode == DRAW ) @@ -1974,7 +1976,7 @@ void pianoRoll::resizeEvent( QResizeEvent * ) } m_topBottomScroll->setValue( m_totalKeysToScroll - m_startKey ); - engine::getSongEditor()->getPlayPos( songEditor::PLAY_PATTERN + engine::getSong()->getPlayPos( song::Mode_PlayPattern ).m_timeLine->setFixedWidth( width() ); m_toolBar->setFixedWidth( width() ); update(); @@ -2052,31 +2054,30 @@ void pianoRoll::play( void ) return; } - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { - if( engine::getSongEditor()->playMode() != - songEditor::PLAY_PATTERN ) + if( engine::getSong()->playMode() != song::Mode_PlayPattern ) { - engine::getSongEditor()->stop(); - engine::getSongEditor()->playPattern( m_pattern ); + engine::getSong()->stop(); + engine::getSong()->playPattern( m_pattern ); m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } else { - engine::getSongEditor()->pause(); + engine::getSong()->pause(); m_playButton->setIcon( embed::getIconPixmap( "play" ) ); } } - else if( engine::getSongEditor()->paused() ) + else if( engine::getSong()->paused() ) { - engine::getSongEditor()->resumeFromPause(); + engine::getSong()->resumeFromPause(); m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); } else { m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - engine::getSongEditor()->playPattern( m_pattern ); + engine::getSong()->playPattern( m_pattern ); } } @@ -2085,7 +2086,7 @@ void pianoRoll::play( void ) void pianoRoll::record( void ) { - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { stop(); } @@ -2095,7 +2096,7 @@ void pianoRoll::record( void ) } m_recording = TRUE; - engine::getSongEditor()->playPattern( m_pattern, FALSE ); + engine::getSong()->playPattern( m_pattern, FALSE ); } @@ -2103,7 +2104,7 @@ void pianoRoll::record( void ) void pianoRoll::stop( void ) { - engine::getSongEditor()->stop(); + engine::getSong()->stop(); m_playButton->setIcon( embed::getIconPixmap( "play" ) ); m_playButton->update(); m_recording = FALSE; @@ -2117,14 +2118,14 @@ void pianoRoll::recordNote( const note & _n ) { if( m_recording == TRUE && validPattern() == TRUE ) { - note n( _n.length(), engine::getSongEditor()->getPlayPos( - songEditor::PLAY_PATTERN ) - _n.length(), + note n( _n.length(), engine::getSong()->getPlayPos( + song::Mode_PlayPattern ) - _n.length(), _n.tone(), _n.octave(), _n.getVolume(), _n.getPanning() ); n.quantizeLength( quantization() ); m_pattern->addNote( n ); update(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } @@ -2301,7 +2302,7 @@ void pianoRoll::getSelectedNotes( noteVector & _selected_notes ) void pianoRoll::copy_to_clipboard( const noteVector & _notes ) const { - multimediaProject mmp( multimediaProject::CLIPBOARD_DATA ); + multimediaProject mmp( multimediaProject::ClipboardData ); QDomElement note_list = mmp.createElement( "note-list" ); mmp.content().appendChild( note_list ); @@ -2356,7 +2357,7 @@ void pianoRoll::cutSelectedNotes( void ) { copy_to_clipboard( selected_notes ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); for( noteVector::iterator it = selected_notes.begin(); it != selected_notes.end(); ++it ) @@ -2401,7 +2402,7 @@ void pianoRoll::pasteNotes( void ) // we only have to do the following lines if we pasted at // least one note... - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); update(); engine::getSongEditor()->update(); } @@ -2430,7 +2431,7 @@ void pianoRoll::deleteSelectedNotes( void ) if( update_after_delete == TRUE ) { - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); update(); engine::getSongEditor()->update(); } @@ -2441,9 +2442,9 @@ void pianoRoll::deleteSelectedNotes( void ) void pianoRoll::updatePosition( const midiTime & _t ) { - if( ( engine::getSongEditor()->playing() && - engine::getSongEditor()->playMode() == - songEditor::PLAY_PATTERN ) || + if( ( engine::getSong()->playing() && + engine::getSong()->playMode() == + song::Mode_PlayPattern ) || m_scrollBack == TRUE ) { const int w = width() - WHITE_KEY_WIDTH; @@ -2564,8 +2565,8 @@ bool pianoRoll::x11Event( XEvent * _xe ) { if( validPattern() ) { - return( m_pattern->getInstrumentTrack()->getPianoWidget() - ->x11Event( _xe ) ); +/* return( m_pattern->getInstrumentTrack()->getPianoWidget() + ->x11Event( _xe ) );*/ } return( FALSE ); } diff --git a/src/core/piano_widget.cpp b/src/core/piano_widget.cpp index 0511c0f277..0fe5a7627f 100644 --- a/src/core/piano_widget.cpp +++ b/src/core/piano_widget.cpp @@ -4,7 +4,7 @@ * piano_widget.cpp - implementation of piano-widget used in channel-window * for testing channel * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -52,25 +52,25 @@ #endif -const keyTypes KEY_ORDER[] = +const KeyTypes KEY_ORDER[] = { // C CIS D DIS E F - WHITE_KEY, BLACK_KEY, WHITE_KEY, BLACK_KEY, WHITE_KEY, WHITE_KEY, + WhiteKey, BlackKey, WhiteKey, BlackKey, WhiteKey, WhiteKey, // FIS G GIS A B H - BLACK_KEY, WHITE_KEY, BLACK_KEY, WHITE_KEY, BLACK_KEY, WHITE_KEY + BlackKey, WhiteKey, BlackKey, WhiteKey, BlackKey, WhiteKey } ; -tones WHITE_KEYS[] = +tones WhiteKeyS[] = { C, D, E, F, G, A, H } ; -QPixmap * pianoWidget::s_whiteKeyPm = NULL; -QPixmap * pianoWidget::s_blackKeyPm = NULL; -QPixmap * pianoWidget::s_whiteKeyPressedPm = NULL; -QPixmap * pianoWidget::s_blackKeyPressedPm = NULL; +QPixmap * pianoView::s_whiteKeyPm = NULL; +QPixmap * pianoView::s_blackKeyPm = NULL; +QPixmap * pianoView::s_whiteKeyPressedPm = NULL; +QPixmap * pianoView::s_blackKeyPressedPm = NULL; const int PIANO_BASE = 11; @@ -81,287 +81,41 @@ const int PW_BLACK_KEY_HEIGHT = 38; const int LABEL_TEXT_SIZE = 7; -pianoWidget::pianoWidget( instrumentTrack * _parent ) : - QWidget( _parent ), - m_instrumentTrack( _parent ), - m_startTone( C ), - m_startOctave( OCTAVE_3 ), - m_lastKey( -1 ), - m_keyCode( 0 ) + + +piano::piano( instrumentTrack * _it ) : + model( _it ), + m_instrumentTrack( _it ) { - connect( m_instrumentTrack->baseNoteModel(), SIGNAL( dataChanged() ), - this, SLOT( update( void ) ) ); - - - setFocusPolicy( Qt::StrongFocus ); - - if( s_whiteKeyPm == NULL ) - { - s_whiteKeyPm = new QPixmap( embed::getIconPixmap( - "white_key" ) ); - } - if( s_blackKeyPm == NULL ) - { - s_blackKeyPm = new QPixmap( embed::getIconPixmap( - "black_key" ) ); - } - if( s_whiteKeyPressedPm == NULL ) - { - s_whiteKeyPressedPm = new QPixmap( embed::getIconPixmap( - "white_key_pressed" ) ); - } - if ( s_blackKeyPressedPm == NULL ) - { - s_blackKeyPressedPm = new QPixmap( embed::getIconPixmap( - "black_key_pressed" ) ); - } - for( int i = 0; i < NOTES_PER_OCTAVE * OCTAVES; ++i ) { m_pressedKeys[i] = FALSE; } - m_pianoScroll = new QScrollBar( Qt::Horizontal, this ); - m_pianoScroll->setRange( 0, WHITE_KEYS_PER_OCTAVE * ( OCTAVES - 3 ) - - 4 ); - m_pianoScroll->setSingleStep( 1 ); - m_pianoScroll->setPageStep( 20 ); - m_pianoScroll->setValue( OCTAVE_3 * WHITE_KEYS_PER_OCTAVE ); - m_pianoScroll->setGeometry( 0, PIANO_BASE + PW_WHITE_KEY_HEIGHT, 250, - 16 ); - // ...and connect it to this widget... - connect( m_pianoScroll, SIGNAL( valueChanged( int ) ), this, - SLOT( pianoScrolled( int ) ) ); - } -pianoWidget::~pianoWidget() +piano::~piano() { } -// gets the key from the given mouse-position -int pianoWidget::getKeyFromMouse( const QPoint & _p ) const +void piano::setKeyState( int _key, bool _on ) { - - int key_num = (int)( (float) _p.x() / (float) PW_WHITE_KEY_WIDTH ); - - for( int i = 0; i <= key_num; ++i ) - { - if( KEY_ORDER[( m_startOctave * NOTES_PER_OCTAVE + - m_startTone +i ) % NOTES_PER_OCTAVE] == - BLACK_KEY ) - { - ++key_num; - } - } - - key_num += m_startOctave * NOTES_PER_OCTAVE + m_startTone; - - // is it a black key? - if( _p.y() < PIANO_BASE + PW_BLACK_KEY_HEIGHT ) - { - // then do extra checking whether the mouse-cursor is over - // a black key - if( key_num > 0 && - KEY_ORDER[( key_num - 1 ) % NOTES_PER_OCTAVE] == - BLACK_KEY && - _p.x() % PW_WHITE_KEY_WIDTH <= - ( PW_WHITE_KEY_WIDTH / 2 ) - - ( PW_BLACK_KEY_WIDTH / 2 ) ) - { - --key_num; - } - if( key_num < NOTES_PER_OCTAVE * OCTAVES - 1 && - KEY_ORDER[( key_num + 1 ) % NOTES_PER_OCTAVE] == - BLACK_KEY && - _p.x() % PW_WHITE_KEY_WIDTH >= - ( PW_WHITE_KEY_WIDTH - - PW_BLACK_KEY_WIDTH / 2 ) ) - { - ++key_num; - } - } - - // some range-checking-stuff - return( tLimit( key_num, 0, NOTES_PER_OCTAVE * OCTAVES - 1 ) ); + m_pressedKeys[tLimit( _key, 0, NOTES_PER_OCTAVE * OCTAVES - 1 )] = _on; + emit dataChanged(); } -// handler for scrolling-event -void pianoWidget::pianoScrolled( int _new_pos ) +int piano::getKeyFromKeycode( int _k ) { - m_startTone = WHITE_KEYS[_new_pos % WHITE_KEYS_PER_OCTAVE]; - m_startOctave = (octaves)( _new_pos / WHITE_KEYS_PER_OCTAVE ); - - update(); -} - - - - -void pianoWidget::contextMenuEvent( QContextMenuEvent * _me ) -{ - if( _me->pos().y() > PIANO_BASE ) - { - QWidget::contextMenuEvent( _me ); - return; - } - - captionMenu contextMenu( tr( "Base note" ) ); - contextMenu.addAction( embed::getIconPixmap( "automation" ), - tr( "&Open in automation editor" ), - m_instrumentTrack->baseNoteModel()->getAutomationPattern(), - SLOT( openInAutomationEditor() ) ); - contextMenu.exec( QCursor::pos() ); -} - - - - -// handler for mouse-click-event -void pianoWidget::mousePressEvent( QMouseEvent * _me ) -{ - if( _me->button() == Qt::LeftButton ) - { - // get pressed key - Uint32 key_num = getKeyFromMouse( _me->pos() ); - if( _me->pos().y() > PIANO_BASE ) - { - int y_diff = _me->pos().y() - PIANO_BASE; - volume vol = (volume)( ( float ) y_diff / - ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == - WHITE_KEY ) ? - PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * - (float) DEFAULT_VOLUME); - if( y_diff < 0 ) - { - vol = 0; - } - else if( y_diff > ( ( KEY_ORDER[key_num % - NOTES_PER_OCTAVE] == - WHITE_KEY ) ? - PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) - { - vol = DEFAULT_VOLUME; - } - // set note on - m_instrumentTrack->processInEvent( - midiEvent( NOTE_ON, 0, key_num, - vol * 127 / 100 ), - midiTime() ); - m_pressedKeys[key_num] = TRUE; - m_lastKey = key_num; - } - else - { - m_instrumentTrack->baseNoteModel()-> - setInitValue( key_num ); - } - - // and let the user see that he pressed a key... :) - update(); - } -} - - - - -// handler for mouse-release-event -void pianoWidget::mouseReleaseEvent( QMouseEvent * _me ) -{ - if( m_lastKey != -1 ) - { - m_instrumentTrack->processInEvent( - midiEvent( NOTE_OFF, 0, m_lastKey, 0 ), midiTime() ); - m_pressedKeys[m_lastKey] = FALSE; - - // and let the user see that he released a key... :) - update(); - - m_lastKey = -1; - } -} - - - - -// handler for mouse-move-event -void pianoWidget::mouseMoveEvent( QMouseEvent * _me ) -{ - int key_num = getKeyFromMouse( _me->pos() ); - int y_diff = _me->pos().y() - PIANO_BASE; - volume vol = (volume)( (float) y_diff / - ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == WHITE_KEY ) ? - PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * - (float)DEFAULT_VOLUME ); - // maybe the user moved the mouse-cursor above or under the - // piano-widget while holding left button so check that and - // correct volume if necessary - if( y_diff < 0 ) - { - vol = 0; - } - else if( y_diff > - ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == WHITE_KEY ) ? - PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) - { - vol = DEFAULT_VOLUME; - } - - // is the calculated key different from current key? (could be the - // user just moved the cursor one pixel left but on the same key) - if( key_num != m_lastKey ) - { - if( m_lastKey != -1 ) - { - m_instrumentTrack->processInEvent( - midiEvent( NOTE_OFF, 0, m_lastKey, 0 ), - midiTime() ); - m_pressedKeys[m_lastKey] = FALSE; - m_lastKey = -1; - } - if( _me->buttons() & Qt::LeftButton ) - { - if( _me->pos().y() > PIANO_BASE ) - { - m_instrumentTrack->processInEvent( - midiEvent( NOTE_ON, 0, key_num, vol ), - midiTime() ); - m_pressedKeys[key_num] = TRUE; - m_lastKey = key_num; - } - else - { - m_instrumentTrack->baseNoteModel()-> - setInitValue( key_num ); - } - } - // and let the user see that he pressed a key... :) - update(); - } - else if( m_pressedKeys[key_num] == TRUE ) - { - m_instrumentTrack->processInEvent( - midiEvent( KEY_PRESSURE, 0, key_num, vol ), - midiTime() ); - } - -} - - - - -int pianoWidget::getKeyFromKeyboard( int _k ) const -{ - switch( m_keyCode ) + switch( _k ) { case 52: return( 0 ); // Y case 39: return( 1 ); // S @@ -400,80 +154,367 @@ int pianoWidget::getKeyFromKeyboard( int _k ) const -void pianoWidget::keyPressEvent( QKeyEvent * _ke ) -{ - int key_num = getKeyFromKeyboard( _ke->key() ) + - ( DEFAULT_OCTAVE - 1 ) * NOTES_PER_OCTAVE; - if( _ke->isAutoRepeat() == FALSE && key_num > -1 ) + +pianoView::pianoView( QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_piano( NULL ), + m_startTone( C ), + m_startOctave( OCTAVE_3 ), + m_lastKey( -1 ), + m_keyCode( 0 ) +{ + if( s_whiteKeyPm == NULL ) { - m_instrumentTrack->processInEvent( - midiEvent( NOTE_ON, 0, key_num, DEFAULT_VOLUME ), - midiTime() ); - m_pressedKeys[key_num] = TRUE; - update(); + s_whiteKeyPm = new QPixmap( embed::getIconPixmap( + "white_key" ) ); } - else + if( s_blackKeyPm == NULL ) { - _ke->ignore(); + s_blackKeyPm = new QPixmap( embed::getIconPixmap( + "black_key" ) ); } + if( s_whiteKeyPressedPm == NULL ) + { + s_whiteKeyPressedPm = new QPixmap( embed::getIconPixmap( + "white_key_pressed" ) ); + } + if ( s_blackKeyPressedPm == NULL ) + { + s_blackKeyPressedPm = new QPixmap( embed::getIconPixmap( + "black_key_pressed" ) ); + } + + setFocusPolicy( Qt::StrongFocus ); + + m_pianoScroll = new QScrollBar( Qt::Horizontal, this ); + m_pianoScroll->setRange( 0, WHITE_KEYS_PER_OCTAVE * ( OCTAVES - 3 ) - + 4 ); + m_pianoScroll->setSingleStep( 1 ); + m_pianoScroll->setPageStep( 20 ); + m_pianoScroll->setValue( OCTAVE_3 * WHITE_KEYS_PER_OCTAVE ); + m_pianoScroll->setGeometry( 0, PIANO_BASE + PW_WHITE_KEY_HEIGHT, 250, + 16 ); + // ...and connect it to this widget... + connect( m_pianoScroll, SIGNAL( valueChanged( int ) ), + this, SLOT( pianoScrolled( int ) ) ); + } -void pianoWidget::keyReleaseEvent( QKeyEvent * _ke ) +pianoView::~pianoView() { - int key_num = getKeyFromKeyboard( _ke->key() ) + - ( DEFAULT_OCTAVE - 1 ) * NOTES_PER_OCTAVE; - if( _ke->isAutoRepeat() == FALSE && key_num > -1 ) - { - m_instrumentTrack->processInEvent( - midiEvent( NOTE_OFF, 0, key_num, 0 ), - midiTime() ); - m_pressedKeys[key_num] = FALSE; - update(); - } - else - { - _ke->ignore(); - } } -void pianoWidget::setKeyState( int _key, bool _on ) +void pianoView::modelChanged( void ) { - m_pressedKeys[tLimit( _key, 0, NOTES_PER_OCTAVE * OCTAVES - 1 )] = _on; - QApplication::postEvent( this, new updateEvent() ); + m_piano = castModel(); + if( m_piano != NULL ) + { + connect( m_piano->m_instrumentTrack->baseNoteModel(), + SIGNAL( dataChanged() ), this, SLOT( update() ) ); + } + } - -void pianoWidget::customEvent( QEvent * ) +// gets the key from the given mouse-position +int pianoView::getKeyFromMouse( const QPoint & _p ) const { + int key_num = (int)( (float) _p.x() / (float) PW_WHITE_KEY_WIDTH ); + + for( int i = 0; i <= key_num; ++i ) + { + if( KEY_ORDER[( m_startOctave * NOTES_PER_OCTAVE + + m_startTone +i ) % NOTES_PER_OCTAVE] == + BlackKey ) + { + ++key_num; + } + } + + key_num += m_startOctave * NOTES_PER_OCTAVE + m_startTone; + + // is it a black key? + if( _p.y() < PIANO_BASE + PW_BLACK_KEY_HEIGHT ) + { + // then do extra checking whether the mouse-cursor is over + // a black key + if( key_num > 0 && + KEY_ORDER[( key_num - 1 ) % NOTES_PER_OCTAVE] == + BlackKey && + _p.x() % PW_WHITE_KEY_WIDTH <= + ( PW_WHITE_KEY_WIDTH / 2 ) - + ( PW_BLACK_KEY_WIDTH / 2 ) ) + { + --key_num; + } + if( key_num < NOTES_PER_OCTAVE * OCTAVES - 1 && + KEY_ORDER[( key_num + 1 ) % NOTES_PER_OCTAVE] == + BlackKey && + _p.x() % PW_WHITE_KEY_WIDTH >= + ( PW_WHITE_KEY_WIDTH - + PW_BLACK_KEY_WIDTH / 2 ) ) + { + ++key_num; + } + } + + // some range-checking-stuff + return( tLimit( key_num, 0, NOTES_PER_OCTAVE * OCTAVES - 1 ) ); +} + + + + +// handler for scrolling-event +void pianoView::pianoScrolled( int _new_pos ) +{ + m_startTone = WhiteKeyS[_new_pos % WHITE_KEYS_PER_OCTAVE]; + m_startOctave = (octaves)( _new_pos / WHITE_KEYS_PER_OCTAVE ); + update(); } -void pianoWidget::focusOutEvent( QFocusEvent * ) +void pianoView::contextMenuEvent( QContextMenuEvent * _me ) { + if( _me->pos().y() > PIANO_BASE || m_piano == NULL ) + { + QWidget::contextMenuEvent( _me ); + return; + } + + captionMenu contextMenu( tr( "Base note" ) ); + contextMenu.addAction( embed::getIconPixmap( "automation" ), + tr( "&Open in automation editor" ), + m_piano->m_instrumentTrack->baseNoteModel()-> + getAutomationPattern(), + SLOT( openInAutomationEditor() ) ); + contextMenu.exec( QCursor::pos() ); +} + + + + +// handler for mouse-click-event +void pianoView::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton && m_piano != NULL ) + { + // get pressed key + Uint32 key_num = getKeyFromMouse( _me->pos() ); + if( _me->pos().y() > PIANO_BASE ) + { + int y_diff = _me->pos().y() - PIANO_BASE; + volume vol = (volume)( ( float ) y_diff / + ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == + WhiteKey ) ? + PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * + (float) DEFAULT_VOLUME); + if( y_diff < 0 ) + { + vol = 0; + } + else if( y_diff > ( ( KEY_ORDER[key_num % + NOTES_PER_OCTAVE] == + WhiteKey ) ? + PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) + { + vol = DEFAULT_VOLUME; + } + // set note on + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_ON, 0, key_num, + vol * 127 / 100 ), + midiTime() ); + m_piano->m_pressedKeys[key_num] = TRUE; + m_lastKey = key_num; + } + else + { + m_piano->m_instrumentTrack->baseNoteModel()-> + setInitValue( key_num ); + } + + // and let the user see that he pressed a key... :) + update(); + } +} + + + + +// handler for mouse-release-event +void pianoView::mouseReleaseEvent( QMouseEvent * _me ) +{ + if( m_lastKey != -1 ) + { + if( m_piano != NULL ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_OFF, 0, m_lastKey, 0 ), + midiTime() ); + m_piano->m_pressedKeys[m_lastKey] = FALSE; + } + + // and let the user see that he released a key... :) + update(); + + m_lastKey = -1; + } +} + + + + +// handler for mouse-move-event +void pianoView::mouseMoveEvent( QMouseEvent * _me ) +{ + if( m_piano == NULL ) + { + return; + } + + int key_num = getKeyFromMouse( _me->pos() ); + int y_diff = _me->pos().y() - PIANO_BASE; + volume vol = (volume)( (float) y_diff / + ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == WhiteKey ) ? + PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * + (float)DEFAULT_VOLUME ); + // maybe the user moved the mouse-cursor above or under the + // piano-widget while holding left button so check that and + // correct volume if necessary + if( y_diff < 0 ) + { + vol = 0; + } + else if( y_diff > + ( ( KEY_ORDER[key_num % NOTES_PER_OCTAVE] == WhiteKey ) ? + PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) + { + vol = DEFAULT_VOLUME; + } + + // is the calculated key different from current key? (could be the + // user just moved the cursor one pixel left but on the same key) + if( key_num != m_lastKey ) + { + if( m_lastKey != -1 ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_OFF, 0, m_lastKey, 0 ), + midiTime() ); + m_piano->m_pressedKeys[m_lastKey] = FALSE; + m_lastKey = -1; + } + if( _me->buttons() & Qt::LeftButton ) + { + if( _me->pos().y() > PIANO_BASE ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_ON, 0, key_num, vol ), + midiTime() ); + m_piano->m_pressedKeys[key_num] = TRUE; + m_lastKey = key_num; + } + else + { + m_piano->m_instrumentTrack->baseNoteModel()-> + setInitValue( key_num ); + } + } + // and let the user see that he pressed a key... :) + update(); + } + else if( m_piano->m_pressedKeys[key_num] == TRUE ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( KEY_PRESSURE, 0, key_num, vol ), + midiTime() ); + } + +} + + + + +void pianoView::keyPressEvent( QKeyEvent * _ke ) +{ + int key_num = piano::getKeyFromKeycode( m_keyCode ) + + ( DEFAULT_OCTAVE - 1 ) * NOTES_PER_OCTAVE; + + if( _ke->isAutoRepeat() == FALSE && key_num > -1 ) + { + if( m_piano != NULL ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_ON, 0, key_num, + DEFAULT_VOLUME ), midiTime() ); + m_piano->m_pressedKeys[key_num] = TRUE; + } + update(); + } + else + { + _ke->ignore(); + } +} + + + + +void pianoView::keyReleaseEvent( QKeyEvent * _ke ) +{ + int key_num = piano::getKeyFromKeycode( m_keyCode ) + + ( DEFAULT_OCTAVE - 1 ) * NOTES_PER_OCTAVE; + if( _ke->isAutoRepeat() == FALSE && key_num > -1 ) + { + if( m_piano != NULL ) + { + m_piano->m_instrumentTrack->processInEvent( + midiEvent( NOTE_OFF, 0, key_num, 0 ), + midiTime() ); + m_piano->m_pressedKeys[key_num] = FALSE; + } + update(); + } + else + { + _ke->ignore(); + } +} + + + + +void pianoView::focusOutEvent( QFocusEvent * ) +{ + if( m_piano == NULL ) + { + return; + } // if we loose focus, we HAVE to note off all running notes because // we don't receive key-release-events anymore and so the notes would // hang otherwise for( int i = 0; i < NOTES_PER_OCTAVE * OCTAVES; ++i ) { - if( m_pressedKeys[i] == TRUE ) + if( m_piano->m_pressedKeys[i] == TRUE ) { - m_instrumentTrack->processInEvent( + m_piano->m_instrumentTrack->processInEvent( midiEvent( NOTE_OFF, 0, i, 0 ), midiTime() ); - m_pressedKeys[i] = FALSE; + m_piano->m_pressedKeys[i] = FALSE; } } update(); @@ -482,7 +523,7 @@ void pianoWidget::focusOutEvent( QFocusEvent * ) -int pianoWidget::getKeyX( int _key_num ) const +int pianoView::getKeyX( int _key_num ) const { int k = m_startOctave*NOTES_PER_OCTAVE + m_startTone; if( _key_num < k ) @@ -495,7 +536,7 @@ int pianoWidget::getKeyX( int _key_num ) const while( k <= _key_num ) { - if( KEY_ORDER[k % NOTES_PER_OCTAVE] == WHITE_KEY ) + if( KEY_ORDER[k % NOTES_PER_OCTAVE] == WhiteKey ) { ++white_cnt; if( white_cnt > 1 ) @@ -524,7 +565,7 @@ int pianoWidget::getKeyX( int _key_num ) const -void pianoWidget::paintEvent( QPaintEvent * ) +void pianoView::paintEvent( QPaintEvent * ) { QPainter p( this ); @@ -544,8 +585,9 @@ void pianoWidget::paintEvent( QPaintEvent * ) p.setPen( QColor ( 0xFF, 0xFF, 0xFF ) ); - int base_key = m_instrumentTrack->baseNoteModel()->value(); - if( KEY_ORDER[base_key % NOTES_PER_OCTAVE] == WHITE_KEY ) + const int base_key = ( m_piano != NULL ) ? + m_piano->m_instrumentTrack->baseNoteModel()->value() : 0; + if( KEY_ORDER[base_key % NOTES_PER_OCTAVE] == WhiteKey ) { p.fillRect( QRect( getKeyX( base_key ), 1, PW_WHITE_KEY_WIDTH-1, PIANO_BASE-2 ), @@ -564,14 +606,14 @@ void pianoWidget::paintEvent( QPaintEvent * ) // draw all white keys... for( int x = 0; x < width(); ) { - while( KEY_ORDER[cur_key%NOTES_PER_OCTAVE] != WHITE_KEY ) + while( KEY_ORDER[cur_key%NOTES_PER_OCTAVE] != WhiteKey ) { ++cur_key; } // draw pressed or not pressed key, depending on state of // current key - if( m_pressedKeys[cur_key] == TRUE ) + if( m_piano && m_piano->m_pressedKeys[cur_key] == TRUE ) { p.drawPixmap( x, PIANO_BASE, *s_whiteKeyPressedPm ); } @@ -600,9 +642,9 @@ void pianoWidget::paintEvent( QPaintEvent * ) int s_key = m_startOctave*NOTES_PER_OCTAVE+m_startTone; if( s_key > 0 && - KEY_ORDER[(tones)( --s_key ) % NOTES_PER_OCTAVE] == BLACK_KEY ) + KEY_ORDER[(tones)( --s_key ) % NOTES_PER_OCTAVE] == BlackKey ) { - if( m_pressedKeys[s_key] == TRUE ) + if( m_piano && m_piano->m_pressedKeys[s_key] == TRUE ) { p.drawPixmap( 0 - PW_WHITE_KEY_WIDTH / 2, PIANO_BASE, *s_blackKeyPressedPm ); @@ -617,11 +659,11 @@ void pianoWidget::paintEvent( QPaintEvent * ) // now draw all black keys... for( int x = 0; x < width(); ) { - if( KEY_ORDER[cur_key%NOTES_PER_OCTAVE] == BLACK_KEY ) + if( KEY_ORDER[cur_key%NOTES_PER_OCTAVE] == BlackKey ) { // draw pressed or not pressed key, depending on // state of current key - if( m_pressedKeys[cur_key] == TRUE ) + if( m_piano && m_piano->m_pressedKeys[cur_key] == TRUE ) { p.drawPixmap( x + PW_WHITE_KEY_WIDTH / 2, PIANO_BASE, @@ -653,7 +695,7 @@ void pianoWidget::paintEvent( QPaintEvent * ) #ifdef BUILD_LINUX -bool pianoWidget::x11Event( XEvent * _xe ) +bool pianoView::x11Event( XEvent * _xe ) { switch( _xe->type ) { diff --git a/src/core/preset_preview_play_handle.cpp b/src/core/preset_preview_play_handle.cpp index 1d2091a4fd..47f9231d73 100644 --- a/src/core/preset_preview_play_handle.cpp +++ b/src/core/preset_preview_play_handle.cpp @@ -53,10 +53,9 @@ public: { setJournalling( FALSE ); m_previewInstrumentTrack = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, + track::create( track::InstrumentTrack, this ) ); m_previewInstrumentTrack->setJournalling( FALSE ); - hide(); } virtual ~previewTrackContainer() @@ -134,7 +133,7 @@ presetPreviewPlayHandle::presetPreviewPlayHandle( mmp.content().firstChild().toElement() ); // preset also contains information about window-states etc. that's why // here we have to make sure that the instrument-track-window is hidden - s_previewTC->previewInstrumentTrack()->hide(); +// s_previewTC->previewInstrumentTrack()->hide(); // make sure, our preset-preview-track does not appear in any MIDI- // devices list, so just disable receiving/sending MIDI-events at all diff --git a/src/core/song.cpp b/src/core/song.cpp new file mode 100644 index 0000000000..a208d0b757 --- /dev/null +++ b/src/core/song.cpp @@ -0,0 +1,1019 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * song.cpp - root of the model-tree + * + * Copyright (c) 2004-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 "song.h" + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + + +#include +#include +#include +#include + + +#include "automation_track.h" +#include "bb_editor.h" +#include "bb_track.h" +#include "config_mgr.h" +#include "embed.h" +#include "envelope_and_lfo_parameters.h" +#include "export_project_dialog.h" +#include "import_filter.h" +#include "instrument_track.h" +#include "main_window.h" +#include "midi_client.h" +#include "mmp.h" +#include "note_play_handle.h" +#include "pattern.h" +#include "piano_roll.h" +#include "project_journal.h" +#include "project_notes.h" +#include "rename_dialog.h" +#include "song_editor.h" +#include "templates.h" +#include "text_float.h" +#include "timeline.h" + + + + +song::song( void ) : + trackContainer(), + m_automationTrack( track::create( track::AutomationTrack, this ) ), + m_tempoModel( DEFAULT_BPM, MIN_BPM, MAX_BPM, intModel::defaultRelStep(), + this ), + m_masterVolumeModel( 100, 0, 200, 1, this ), + m_masterPitchModel( 0, -12, 12, 1, this ), + m_fileName(), + m_oldFileName(), + m_modified( FALSE ), + m_exporting( FALSE ), + m_playing( FALSE ), + m_paused( FALSE ), + m_loadingProject( FALSE ), + m_playMode( Mode_PlaySong ), + m_trackToPlay( NULL ), + m_patternToPlay( NULL ), + m_loopPattern( FALSE ) +{ + m_tempoModel.setTrack( m_automationTrack ); + connect( &m_tempoModel, SIGNAL( dataChanged() ), + this, SLOT( setTempo() ) ); + connect( &m_tempoModel, SIGNAL( dataUnchanged() ), + this, SLOT( setTempo() ) ); + + + connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), this, + SLOT( updateFramesPerTact64th() ) ); + + + m_masterVolumeModel.setTrack( m_automationTrack ); + m_masterPitchModel.setTrack( m_automationTrack ); + + connect( &m_masterVolumeModel, SIGNAL( dataChanged() ), + this, SLOT( masterVolumeChanged() ) ); +/* connect( &m_masterPitchModel, SIGNAL( dataChanged() ), + this, SLOT( masterPitchChanged() ) );*/ + +} + + + + +song::~song() +{ + m_playing = FALSE; + delete m_automationTrack; +} + + + + +void song::masterVolumeChanged( void ) +{ + engine::getMixer()->setMasterGain( m_masterVolumeModel.value() / + 100.0f ); +} + + + + +void song::setTempo( void ) +{ + const bpm_t tempo = m_tempoModel.value(); + playHandleVector & phv = engine::getMixer()->playHandles(); + for( playHandleVector::iterator it = phv.begin(); it != phv.end(); + ++it ) + { + notePlayHandle * nph = dynamic_cast( *it ); + if( nph && !nph->released() ) + { + nph->resize( tempo ); + } + } + +// m_bpmSpinBox->setInitValue( _new_bpm ); + engine::updateFramesPerTact64th(); + emit tempoChanged( tempo ); +} + + + + +void song::doActions( void ) +{ + while( !m_actions.empty() ) + { + switch( m_actions.front() ) + { + case ActionStop: + { + timeLine * tl = + m_playPos[m_playMode].m_timeLine; + m_playing = FALSE; + if( tl != NULL ) + { + + switch( tl->behaviourAtStop() ) + { + case timeLine::BackToZero: + m_playPos[m_playMode].setTact( 0 ); + m_playPos[m_playMode].setTact64th( 0 ); + break; + + case timeLine::BackToStart: + if( tl->savedPos() >= 0 ) + { + m_playPos[m_playMode].setTact( + tl->savedPos().getTact() ); + m_playPos[m_playMode].setTact64th( + tl->savedPos().getTact64th() ); + tl->savePos( -1 ); + } + break; + + case timeLine::KeepStopPosition: + default: + break; + } + + } + else + { + m_playPos[m_playMode].setTact( 0 ); + m_playPos[m_playMode].setTact64th( 0 ); + } + + m_playPos[m_playMode].setCurrentFrame( 0 ); + + // remove all note-play-handles that are active + engine::getMixer()->clear(); + + break; + } + + case ActionPlaySong: + m_playMode = Mode_PlaySong; + m_playing = TRUE; + break; + + case ActionPlayTrack: + m_playMode = Mode_PlayTrack; + m_playing = TRUE; + break; + + case ActionPlayBB: + m_playMode = Mode_PlayBB; + m_playing = TRUE; + break; + + case ActionPlayPattern: + m_playMode = Mode_PlayPattern; + m_playing = TRUE; + break; + + case ActionPause: + m_playing = FALSE;// just set the play-flag + m_paused = TRUE; + break; + + case ActionResumeFromPause: + m_playing = TRUE;// just set the play-flag + m_paused = FALSE; + break; + } + + // a second switch for saving pos when starting to play + // anything (need pos for restoring it later in certain + // timeline-modes) + switch( m_actions.front() ) + { + case ActionPlaySong: + case ActionPlayTrack: + case ActionPlayBB: + case ActionPlayPattern: + { + timeLine * tl = + m_playPos[m_playMode].m_timeLine; + if( tl != NULL ) + { + tl->savePos( m_playPos[m_playMode] ); + } + break; + } + + // keep GCC happy... + default: + break; + } + + m_actions.erase( m_actions.begin() ); + + } + +} + + + + +void song::processNextBuffer( void ) +{ + doActions(); + + if( m_playing == FALSE ) + { + return; + } + + QList trackList; + Sint16 tco_num = -1; + + switch( m_playMode ) + { + case Mode_PlaySong: + trackList = tracks(); + // at song-start we have to reset the LFOs + if( m_playPos[Mode_PlaySong] == 0 ) + { + envelopeAndLFOParameters::resetLFO(); + } + break; + + case Mode_PlayTrack: + trackList.push_back( m_trackToPlay ); + break; + + case Mode_PlayBB: + if( engine::getBBTrackContainer()->numOfBBs() > 0 ) + { + tco_num = engine::getBBTrackContainer()-> + currentBB(); + trackList.push_back( bbTrack::findBBTrack( + tco_num ) ); + } + break; + + case Mode_PlayPattern: + if( m_patternToPlay != NULL ) + { + tco_num = m_patternToPlay->getTrack()-> + getTCONum( m_patternToPlay ); + trackList.push_back( + m_patternToPlay->getTrack() ); + } + break; + + default: + return; + + } + + if( trackList.empty() == TRUE ) + { + return; + } + + // check for looping-mode and act if neccessary + timeLine * tl = m_playPos[m_playMode].m_timeLine; + bool check_loop = tl != NULL && m_exporting == FALSE && + tl->loopPointsEnabled() && + !( m_playMode == Mode_PlayPattern && + m_patternToPlay->freezing() == TRUE ); + if( check_loop ) + { + if( m_playPos[m_playMode] < tl->loopBegin() || + m_playPos[m_playMode] >= tl->loopEnd() ) + { + m_playPos[m_playMode].setTact( + tl->loopBegin().getTact() ); + m_playPos[m_playMode].setTact64th( + tl->loopBegin().getTact64th() ); + } + } + + f_cnt_t total_frames_played = 0; + float frames_per_tact64th = engine::framesPerTact64th(); + + while( total_frames_played + < engine::getMixer()->framesPerPeriod() ) + { + f_cnt_t played_frames = engine::getMixer() + ->framesPerPeriod() - total_frames_played; + + float current_frame = m_playPos[m_playMode].currentFrame(); + // did we play a 64th of a tact? + if( current_frame >= frames_per_tact64th ) + { + int tact64th = m_playPos[m_playMode].getTact64th() + + (int)( current_frame / frames_per_tact64th ); + // did we play a whole tact? + if( tact64th >= 64 ) + { + // per default we just continue playing even if + // there's no more stuff to play + // (song-play-mode) + int max_tact = m_playPos[m_playMode].getTact() + + 2; + + // then decide whether to go over to next tact + // or to loop back to first tact + if( m_playMode == Mode_PlayBB ) + { + max_tact = engine::getBBTrackContainer() + ->lengthOfCurrentBB(); + } + else if( m_playMode == Mode_PlayPattern && + m_loopPattern == TRUE && + tl != NULL && + tl->loopPointsEnabled() == FALSE ) + { + max_tact = m_patternToPlay->length() + .getTact(); + } + if( m_playPos[m_playMode].getTact() + 1 + < max_tact ) + { + // next tact + m_playPos[m_playMode].setTact( + m_playPos[m_playMode].getTact() + + 1 ); + } + else + { + // first tact + m_playPos[m_playMode].setTact( 0 ); + } + } + m_playPos[m_playMode].setTact64th( tact64th % 64 ); + + if( check_loop ) + { + if( m_playPos[m_playMode] >= tl->loopEnd() ) + { + m_playPos[m_playMode].setTact( + tl->loopBegin().getTact() ); + m_playPos[m_playMode].setTact64th( + tl->loopBegin().getTact64th() ); + } + } + + current_frame = fmodf( current_frame, + frames_per_tact64th ); + m_playPos[m_playMode].setCurrentFrame( current_frame ); + } + + f_cnt_t last_frames = (f_cnt_t)frames_per_tact64th + - (f_cnt_t)current_frame; + // skip last frame fraction + if( last_frames == 0 ) + { + ++total_frames_played; + m_playPos[m_playMode].setCurrentFrame( current_frame + + 1.0f ); + continue; + } + // do we have some samples left in this tact64th but this are + // less then samples we have to play? + if( last_frames < played_frames ) + { + // then set played_samples to remaining samples, the + // rest will be played in next loop + played_frames = last_frames; + } + + if( (f_cnt_t)current_frame == 0 ) + { + if( m_playMode == Mode_PlaySong ) + { + m_automationTrack->play( m_playPos[m_playMode], + played_frames, + total_frames_played, tco_num ); + } + + // loop through all tracks and play them + for( int i = 0; i < trackList.size(); ++i ) + { + trackList[i]->play( m_playPos[m_playMode], + played_frames, + total_frames_played, tco_num ); + } + } + + // update frame-counters + total_frames_played += played_frames; + m_playPos[m_playMode].setCurrentFrame( played_frames + + current_frame ); + } +} + + + + +bool song::realTimeTask( void ) const +{ + return( !( m_exporting == TRUE || ( m_playMode == Mode_PlayPattern && + m_patternToPlay != NULL && + m_patternToPlay->freezing() == TRUE ) ) ); +} + + + + +void song::play( void ) +{ + if( m_playing == TRUE ) + { + if( m_playMode != Mode_PlaySong ) + { + // make sure, bb-editor updates/resets it play-button + engine::getBBTrackContainer()->stop(); + //pianoRoll::inst()->stop(); + } + else + { + pause(); + return; + } + } + m_actions.push_back( ActionPlaySong ); +} + + + + +void song::playTrack( track * _trackToPlay ) +{ + if( m_playing == TRUE ) + { + stop(); + } + m_trackToPlay = _trackToPlay; + + m_actions.push_back( ActionPlayTrack ); +} + + + + +void song::playBB( void ) +{ + if( m_playing == TRUE ) + { + stop(); + } + m_actions.push_back( ActionPlayBB ); +} + + + + +void song::playPattern( pattern * _patternToPlay, bool _loop ) +{ + if( m_playing == TRUE ) + { + stop(); + } + m_patternToPlay = _patternToPlay; + m_loopPattern = _loop; + if( m_patternToPlay != NULL ) + { + m_actions.push_back( ActionPlayPattern ); + } +} + + + + +tact song::lengthInTacts( void ) const +{ + tact len = 0; + const QList & ctl = tracks(); + for( int i = 0; i < ctl.size(); ++i ) + { + len = tMax( ctl[i]->length(), len ); + } + return( len ); +} + + + + +void song::setPlayPos( tact _tact_num, tact64th _t_64th, PlayModes _play_mode ) +{ + m_playPos[_play_mode].setTact( _tact_num ); + m_playPos[_play_mode].setTact64th( _t_64th ); + m_playPos[_play_mode].setCurrentFrame( 0.0f ); +} + + + + +void song::stop( void ) +{ + m_actions.push_back( ActionStop ); +} + + + + + + +void song::pause( void ) +{ + m_actions.push_back( ActionPause ); +} + + + + +void song::resumeFromPause( void ) +{ + m_actions.push_back( ActionResumeFromPause ); +} + + + + +void song::startExport( void ) +{ + stop(); + doActions(); + + play(); + doActions(); + + m_exporting = TRUE; +} + + + + +void song::stopExport( void ) +{ + stop(); + m_exporting = FALSE; +} + + + + + + +void song::insertBar( void ) +{ + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + tl[i]->insertTact( m_playPos[Mode_PlaySong] ); + } +} + + + + +void song::removeBar( void ) +{ + QList tl = tracks(); + for( int i = 0; i < tl.size(); ++i ) + { + tl[i]->removeTact( m_playPos[Mode_PlaySong] ); + } +} + + + + +void song::addBBTrack( void ) +{ + track * t = track::create( track::BBTrack, this ); + engine::getBBTrackContainer()->setCurrentBB( + bbTrack::numOfBBTrack( t ) ); +} + + + + +void song::addSampleTrack( void ) +{ + (void) track::create( track::SampleTrack, this ); +} + + + + +bpm_t song::getTempo( void ) +{ + return( m_tempoModel.value() ); +} + + + + +automationPattern * song::tempoAutomationPattern( void ) +{ + return( m_tempoModel.getAutomationPattern() ); +} + + + + +void song::clearProject( void ) +{ + engine::getProjectJournal()->setJournalling( FALSE ); + + if( m_playing ) + { + stop(); + } + + engine::getMixer()->lock(); + if( engine::getBBEditor() ) + { + engine::getBBEditor()->clearAllTracks(); + } + if( engine::getSongEditor() ) + { + engine::getSongEditor()->clearAllTracks(); + } + QCoreApplication::sendPostedEvents(); + engine::getBBTrackContainer()->clearAllTracks(); + clearAllTracks(); + + engine::getAutomationEditor()->setCurrentPattern( NULL ); + m_tempoModel.getAutomationPattern()->clear(); + m_masterVolumeModel.getAutomationPattern()->clear(); + m_masterPitchModel.getAutomationPattern()->clear(); + + engine::getMixer()->unlock(); + + engine::getProjectNotes()->clear(); + + engine::getProjectJournal()->clearInvalidJournallingObjects(); + engine::getProjectJournal()->clearJournal(); + + engine::getProjectJournal()->setJournalling( TRUE ); +} + + + + + +// create new file +void song::createNewProject( void ) +{ + QString default_template = configManager::inst()->userProjectsDir() + + "templates/default.mpt"; + if( QFile::exists( default_template ) ) + { + createNewProjectFromTemplate( default_template ); + return; + } + + default_template = configManager::inst()->factoryProjectsDir() + + "templates/default.mpt"; + if( QFile::exists( default_template ) ) + { + createNewProjectFromTemplate( default_template ); + return; + } + + m_loadingProject = TRUE; + + clearProject(); + + engine::getProjectJournal()->setJournalling( FALSE ); + + m_fileName = m_oldFileName = ""; + + engine::getMainWindow()->resetWindowTitle(); + + track * t; + t = track::create( track::InstrumentTrack, this ); + dynamic_cast< instrumentTrack * >( t )->loadInstrument( + "tripleoscillator" ); +// track::create( track::SampleTrack, this ); + t = track::create( track::InstrumentTrack, + engine::getBBTrackContainer() ); + dynamic_cast< instrumentTrack * >( t )->loadInstrument( + "tripleoscillator" ); + track::create( track::BBTrack, this ); + + m_tempoModel.setInitValue( DEFAULT_BPM ); + m_masterVolumeModel.setInitValue( 100 ); + m_masterPitchModel.setInitValue( 0 ); + + engine::getProjectJournal()->setJournalling( TRUE ); + + m_loadingProject = FALSE; +} + + + + +void FASTCALL song::createNewProjectFromTemplate( const QString & + _template ) +{ + loadProject( _template ); + // clear file-name so that user doesn't overwrite template when + // saving... + m_fileName = m_oldFileName = ""; +} + + + + +// load given song +void FASTCALL song::loadProject( const QString & _file_name ) +{ + m_loadingProject = TRUE; + + clearProject(); + + engine::getProjectJournal()->setJournalling( FALSE ); + + m_fileName = _file_name; + m_oldFileName = _file_name; + + multimediaProject mmp( m_fileName ); + // if file could not be opened, head-node is null and we create + // new project + if( mmp.head().isNull() ) + { + createNewProject(); + return; + } + + engine::getMainWindow()->resetWindowTitle(); + + // get the header information from the DOM + m_tempoModel.loadSettings( mmp.head(), "bpm" ); + m_masterVolumeModel.loadSettings( mmp.head(), "mastervol" ); + m_masterPitchModel.loadSettings( mmp.head(), "masterpitch" ); + + // reset loop-point-state + m_playPos[Mode_PlaySong].m_timeLine->toggleLoopPoints( 0 ); + + QDomNode node = mmp.content().firstChild(); + while( !node.isNull() ) + { + if( node.isElement() ) + { + if( node.nodeName() == "trackcontainer" ) + { + ( (journallingObject *)( this ) )-> + restoreState( node.toElement() ); + } + else if( node.nodeName() == + engine::getPianoRoll()->nodeName() ) + { + engine::getPianoRoll()->restoreState( + node.toElement() ); + } + else if( node.nodeName() == + engine::getAutomationEditor()->nodeName() ) + { + engine::getAutomationEditor()->restoreState( + node.toElement() ); + } + else if( node.nodeName() == + engine::getProjectNotes()->nodeName() ) + { + ( (journallingObject *)( engine:: + getProjectNotes() ) )-> + restoreState( node.toElement() ); + } + else if( node.nodeName() == + m_playPos[Mode_PlaySong].m_timeLine->nodeName() ) + { + m_playPos[Mode_PlaySong].m_timeLine->restoreState( + node.toElement() ); + } + } + node = node.nextSibling(); + } + + configManager::inst()->addRecentlyOpenedProject( _file_name ); + + engine::getProjectJournal()->setJournalling( TRUE ); + + m_loadingProject = FALSE; +} + + + + +// save current song +bool song::saveProject( void ) +{ + multimediaProject mmp( multimediaProject::SongProject ); + + m_tempoModel.saveSettings( mmp, mmp.head(), "bpm" ); + m_masterVolumeModel.saveSettings( mmp, mmp.head(), "mastervol" ); + m_masterPitchModel.saveSettings( mmp, mmp.head(), "masterpitch" ); + + + ( (journallingObject *)( this ) )->saveState( mmp, mmp.content() ); + + engine::getPianoRoll()->saveState( mmp, mmp.content() ); + engine::getAutomationEditor()->saveState( mmp, mmp.content() ); + ( (journallingObject *)( engine::getProjectNotes() ) )->saveState( mmp, + mmp.content() ); + m_playPos[Mode_PlaySong].m_timeLine->saveState( mmp, mmp.content() ); + + m_fileName = mmp.nameWithExtension( m_fileName ); + if( mmp.writeFile( m_fileName, m_oldFileName == "" || + m_fileName != m_oldFileName ) == TRUE ) + { + textFloat::displayMessage( tr( "Project saved" ), + tr( "The project %1 is now saved." + ).arg( m_fileName ), + embed::getIconPixmap( "project_save", 24, 24 ), + 2000 ); + configManager::inst()->addRecentlyOpenedProject( m_fileName ); + engine::getMainWindow()->resetWindowTitle(); + } + else + { + textFloat::displayMessage( tr( "Project NOT saved." ), + tr( "The project %1 was not saved!" ).arg( + m_fileName ), + embed::getIconPixmap( "error" ), 4000 ); + return( FALSE ); + } + return( TRUE ); +} + + + + +// save current song in given filename +bool FASTCALL song::saveProjectAs( const QString & _file_name ) +{ + QString o = m_oldFileName; + m_oldFileName = m_fileName; + m_fileName = _file_name; + if( saveProject() == FALSE ) + { + m_fileName = m_oldFileName; + m_oldFileName = o; + return( FALSE ); + } + m_oldFileName = m_fileName; + return( TRUE ); +} + + + + +void song::importProject( void ) +{ + QFileDialog ofd( NULL, tr( "Import file" ) ); + ofd.setDirectory( configManager::inst()->userProjectsDir() ); + ofd.setFileMode( QFileDialog::ExistingFiles ); + if( ofd.exec () == QDialog::Accepted && !ofd.selectedFiles().isEmpty() ) + { + importFilter::import( ofd.selectedFiles()[0], this ); + } +} + + +#warning TODO: move somewhere else +static inline QString baseName( const QString & _file ) +{ + return( QFileInfo( _file ).absolutePath() + "/" + + QFileInfo( _file ).completeBaseName() ); +} + + +void song::exportProject( void ) +{ + QString base_filename; + + if( m_fileName != "" ) + { + base_filename = baseName( m_fileName ); + } + else + { + base_filename = tr( "untitled" ); + } + base_filename += fileEncodeDevices[0].m_extension; + + QFileDialog efd( engine::getMainWindow() ); + efd.setFileMode( QFileDialog::AnyFile ); + + int idx = 0; + QStringList types; + while( fileEncodeDevices[idx].m_fileType != NULL_FILE ) + { + types << tr( fileEncodeDevices[idx].m_description ); + ++idx; + } + efd.setFilters( types ); + efd.selectFile( base_filename ); + efd.setWindowTitle( tr( "Select file for project-export..." ) ); + + if( efd.exec() == QDialog::Accepted && + !efd.selectedFiles().isEmpty() && efd.selectedFiles()[0] != "" + ) + { + const QString export_file_name = efd.selectedFiles()[0]; + if( QFileInfo( export_file_name ).exists() == TRUE && + QMessageBox::warning( engine::getMainWindow(), + tr( "File already exists" ), + tr( "The file \"%1\" already " + "exists. Do you want " + "to overwrite it?" + ).arg( QFileInfo( + export_file_name ).fileName() ), + QMessageBox::Yes, + QMessageBox::No | + QMessageBox::Escape | + QMessageBox::Default ) + == QMessageBox::No ) + { + return; + } + exportProjectDialog epd( export_file_name, + engine::getMainWindow() ); + epd.exec(); + } +} + + + + +void song::updateFramesPerTact64th( void ) +{ + engine::updateFramesPerTact64th(); +} + + + + +void song::setModified( void ) +{ + if( !m_loadingProject ) + { + m_modified = TRUE; + engine::getMainWindow()->resetWindowTitle(); + } +} + + + + +#include "song.moc" + + +#endif diff --git a/src/core/song_editor.cpp b/src/core/song_editor.cpp index a4695b986e..655d82d393 100644 --- a/src/core/song_editor.cpp +++ b/src/core/song_editor.cpp @@ -1,9 +1,9 @@ #ifndef SINGLE_SOURCE_COMPILE /* - * song_editor.cpp - basic window for editing song + * song_editor.cpp - basic window for song-editing * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -80,21 +80,9 @@ -songEditor::songEditor( void ) : - m_automationTrack( track::create( track::AUTOMATION_TRACK, this ) ), - m_tempoModel( DEFAULT_BPM, MIN_BPM, MAX_BPM ), - m_masterVolumeModel( 100, 0, 200, 1 ), - m_masterPitchModel( 0, -12, 12, 1 ), - m_fileName( "" ), - m_oldFileName( "" ), - m_exporting( FALSE ), - m_playing( FALSE ), - m_paused( FALSE ), - m_loadingProject( FALSE ), - m_playMode( PLAY_SONG ), - m_trackToPlay( NULL ), - m_patternToPlay( NULL ), - m_loopPattern( FALSE ), +songEditor::songEditor( song * _song ) : + trackContainerView( _song ), + m_s( _song ), m_scrollBack( FALSE ) { setWindowTitle( tr( "Song-Editor" ) ); @@ -106,10 +94,11 @@ songEditor::songEditor( void ) : // create time-line timeLine * tl = new timeLine( TRACK_OP_WIDTH + DEFAULT_SETTINGS_WIDGET_WIDTH, 32, - pixelsPerTact(), m_playPos[PLAY_SONG], + pixelsPerTact(), + m_s->m_playPos[song::Mode_PlaySong], m_currentPosition, this ); connect( this, SIGNAL( positionChanged( const midiTime & ) ), - m_playPos[PLAY_SONG].m_timeLine, + m_s->m_playPos[song::Mode_PlaySong].m_timeLine, SLOT( updatePosition( const midiTime & ) ) ); connect( tl, SIGNAL( positionChanged( const midiTime & ) ), this, SLOT( updatePosition( const midiTime & ) ) ); @@ -120,19 +109,11 @@ songEditor::songEditor( void ) : engine::getMainWindow()->addSpacingToToolBar( 10 ); - m_tempoModel.setTrack( m_automationTrack ); m_tempoSpinBox = new lcdSpinBox( 3, tb, tr( "Tempo" ) ); - m_tempoSpinBox->setModel( &m_tempoModel ); + m_tempoSpinBox->setModel( &m_s->m_tempoModel ); m_tempoSpinBox->setLabel( tr( "TEMPO/BPM" ) ); toolTip::add( m_tempoSpinBox, tr( "tempo of song" ) ); - connect( &m_tempoModel, SIGNAL( dataChanged() ), - this, SLOT( setTempo() ) ); - connect( &m_tempoModel, SIGNAL( dataUnchanged() ), - this, SLOT( setTempo() ) ); - connect( m_tempoSpinBox, SIGNAL( manualChange() ), this, - SLOT( setModified() ) ); - m_tempoSpinBox->setWhatsThis( tr( "The tempo of a song is specified in beats per minute " "(BPM). If you want to change the tempo of your " @@ -155,7 +136,8 @@ songEditor::songEditor( void ) : engine::getMainWindow()->addWidgetToToolBar( hq_btn, 1, col ); - toolButton * cp_btn = new toolButton( embed::getIconPixmap( "auto_limit" ), + toolButton * cp_btn = new toolButton( + embed::getIconPixmap( "auto_limit" ), tr( "Auto limiter" ), NULL, NULL, tb ); cp_btn->setCheckable( TRUE ); @@ -175,9 +157,9 @@ songEditor::songEditor( void ) : QLabel * master_vol_lbl = new QLabel( tb ); master_vol_lbl->setPixmap( embed::getIconPixmap( "master_volume" ) ); - m_masterVolumeModel.setTrack( m_automationTrack ); - m_masterVolumeSlider = new automatableSlider( tb, tr( "Master volume" ) ); - m_masterVolumeSlider->setModel( &m_masterVolumeModel ); + m_masterVolumeSlider = new automatableSlider( tb, + tr( "Master volume" ) ); + m_masterVolumeSlider->setModel( &m_s->m_masterVolumeModel ); m_masterVolumeSlider->setOrientation( Qt::Vertical ); m_masterVolumeSlider->setPageStep( 1 ); m_masterVolumeSlider->setTickPosition( QSlider::TicksLeft ); @@ -209,9 +191,8 @@ songEditor::songEditor( void ) : master_pitch_lbl->setPixmap( embed::getIconPixmap( "master_pitch" ) ); master_pitch_lbl->setFixedHeight( 64 ); - m_masterPitchModel.setTrack( m_automationTrack ); m_masterPitchSlider = new automatableSlider( tb, tr( "Master pitch" ) ); - m_masterPitchSlider->setModel( &m_masterPitchModel ); + m_masterPitchSlider->setModel( &m_s->m_masterPitchModel ); m_masterPitchSlider->setOrientation( Qt::Vertical ); m_masterPitchSlider->setPageStep( 1 ); m_masterPitchSlider->setTickPosition( QSlider::TicksLeft ); @@ -272,22 +253,22 @@ songEditor::songEditor( void ) : // fill own tool-bar m_playButton = new toolButton( embed::getIconPixmap( "play" ), tr( "Play song (Space)" ), - this, SLOT( play() ), m_toolBar ); + m_s, SLOT( play() ), m_toolBar ); m_stopButton = new toolButton( embed::getIconPixmap( "stop" ), tr( "Stop song (Space)" ), - this, SLOT( stop() ), m_toolBar ); + m_s, SLOT( stop() ), m_toolBar ); m_addBBTrackButton = new toolButton( embed::getIconPixmap( "add_bb_track" ), tr( "Add beat/bassline" ), - this, SLOT( addBBTrack() ), + m_s, SLOT( addBBTrack() ), m_toolBar ); m_addSampleTrackButton = new toolButton( embed::getIconPixmap( "add_sample_track" ), tr( "Add sample-track" ), - this, SLOT( addSampleTrack() ), + m_s, SLOT( addSampleTrack() ), m_toolBar ); m_drawModeButton = new toolButton( embed::getIconPixmap( @@ -404,8 +385,6 @@ songEditor::songEditor( void ) : songEditor::~songEditor() { - m_playing = FALSE; - delete m_automationTrack; } @@ -413,8 +392,8 @@ songEditor::~songEditor() void songEditor::paintEvent( QPaintEvent * _pe ) { - m_leftRightScroll->setMaximum( lengthInTacts() ); - trackContainer::paintEvent( _pe ); + m_leftRightScroll->setMaximum( m_s->lengthInTacts() ); + trackContainerView::paintEvent( _pe ); } @@ -426,48 +405,48 @@ void songEditor::keyPressEvent( QKeyEvent * _ke ) engine::getMainWindow()->isShiftPressed() == TRUE && _ke->key() == Qt::Key_Insert ) { - insertBar(); + m_s->insertBar(); } else if(/* _ke->modifiers() & Qt::ShiftModifier &&*/ engine::getMainWindow()->isShiftPressed() == TRUE && _ke->key() == Qt::Key_Delete ) { - removeBar(); + m_s->removeBar(); } else if( _ke->key() == Qt::Key_Left ) { - tact interesting_tact = currentTact(); + tact interesting_tact = m_s->currentTact(); if( interesting_tact > 0 ) { - setPlayPos( --interesting_tact, currentTact64th(), - PLAY_SONG ); + m_s->setPlayPos( --interesting_tact, + m_s->currentTact64th(), + song::Mode_PlaySong ); } - } else if( _ke->key() == Qt::Key_Right ) { - tact interesting_tact = currentTact(); + tact interesting_tact = m_s->currentTact(); if( interesting_tact < MAX_SONG_LENGTH ) { - setPlayPos( ++interesting_tact, currentTact64th(), - PLAY_SONG ); + m_s->setPlayPos( ++interesting_tact, + m_s->currentTact64th(), + song::Mode_PlaySong ); } - } else if( _ke->key() == Qt::Key_Space ) { - if( playing() ) + if( m_s->playing() ) { - stop(); + m_s->stop(); } else { - play(); + m_s->play(); } } else if( _ke->key() == Qt::Key_Home ) { - setPlayPos( 0, 0, PLAY_SONG ); + m_s->setPlayPos( 0, 0, song::Mode_PlaySong ); } else { @@ -509,8 +488,8 @@ void songEditor::wheelEvent( QWheelEvent * _we ) 100 / DEFAULT_PIXELS_PER_TACT ) ) + "%" ) ); // update timeline - m_playPos[PLAY_SONG].m_timeLine->setPixelsPerTact( - pixelsPerTact() ); + m_s->m_playPos[song::Mode_PlaySong].m_timeLine-> + setPixelsPerTact( pixelsPerTact() ); // and make sure, all TCO's are resized and relocated realignTracks(); } @@ -533,7 +512,7 @@ void songEditor::wheelEvent( QWheelEvent * _we ) void songEditor::masterVolumeChanged( int _new_val ) { masterVolumeMoved( _new_val ); - if( m_mvsStatus->isVisible() == FALSE && m_loadingProject == FALSE + if( m_mvsStatus->isVisible() == FALSE && m_s->m_loadingProject == FALSE && m_masterVolumeSlider->showStatus() ) { m_mvsStatus->reparent( m_masterVolumeSlider ); @@ -557,7 +536,7 @@ void songEditor::masterVolumePressed( void ) QPoint( 0, 0 ) ) + QPoint( m_masterVolumeSlider->width() + 2, -2 ) ); m_mvsStatus->show(); - masterVolumeMoved( m_masterVolumeModel.value() ); + masterVolumeMoved( m_s->m_masterVolumeModel.value() ); } @@ -582,7 +561,7 @@ void songEditor::masterVolumeReleased( void ) void songEditor::masterPitchChanged( int _new_val ) { masterPitchMoved( _new_val ); - if( m_mpsStatus->isVisible() == FALSE && m_loadingProject == FALSE + if( m_mpsStatus->isVisible() == FALSE && m_s->m_loadingProject == FALSE && m_masterPitchSlider->showStatus() ) { m_mpsStatus->reparent( m_masterPitchSlider ); @@ -605,7 +584,7 @@ void songEditor::masterPitchPressed( void ) QPoint( 0, 0 ) ) + QPoint( m_masterPitchSlider->width() + 2, -2 ) ); m_mpsStatus->show(); - masterPitchMoved( m_masterPitchModel.value() ); + masterPitchMoved( m_s->m_masterPitchModel.value() ); } @@ -630,7 +609,8 @@ void songEditor::masterPitchReleased( void ) void songEditor::updatePosition( const midiTime & _t ) { - if( ( m_playing && m_playMode == PLAY_SONG ) || m_scrollBack == TRUE ) + if( ( m_s->m_playing && m_s->m_playMode == song::Mode_PlaySong ) || + m_scrollBack == TRUE ) { const int w = width() - DEFAULT_SETTINGS_WIDGET_WIDTH - TRACK_OP_WIDTH; @@ -657,458 +637,18 @@ void songEditor::zoomingChanged( void ) const QString & zfac = m_zoomingComboBox->model()->currentText(); setPixelsPerTact( zfac.left( zfac.length() - 1 ).toInt() * DEFAULT_PIXELS_PER_TACT / 100 ); - m_playPos[PLAY_SONG].m_timeLine->setPixelsPerTact( pixelsPerTact() ); + m_s->m_playPos[song::Mode_PlaySong].m_timeLine-> + setPixelsPerTact( pixelsPerTact() ); realignTracks(); } -void songEditor::setTempo( void ) -{ - const bpm_t tempo = m_tempoModel.value(); - playHandleVector & phv = engine::getMixer()->playHandles(); - for( playHandleVector::iterator it = phv.begin(); it != phv.end(); - ++it ) - { - notePlayHandle * nph = dynamic_cast( *it ); - if( nph && !nph->released() ) - { - nph->resize( tempo ); - } - } - -// m_bpmSpinBox->setInitValue( _new_bpm ); - engine::updateFramesPerTact64th(); - emit tempoChanged( tempo ); -} - - - - -void songEditor::doActions( void ) -{ - while( !m_actions.empty() ) - { - switch( m_actions.front() ) - { - case ACT_STOP_PLAY: - { - timeLine * tl = - m_playPos[m_playMode].m_timeLine; - m_playing = FALSE; - if( tl != NULL ) - { - - switch( tl->behaviourAtStop() ) - { - case timeLine::BACK_TO_ZERO: - m_playPos[m_playMode].setTact( 0 ); - m_playPos[m_playMode].setTact64th( 0 ); - break; - - case timeLine::BACK_TO_START: - if( tl->savedPos() >= 0 ) - { - m_playPos[m_playMode].setTact( - tl->savedPos().getTact() ); - m_playPos[m_playMode].setTact64th( - tl->savedPos().getTact64th() ); - tl->savePos( -1 ); - } - break; - - case timeLine::KEEP_STOP_POSITION: - default: - break; - } - - } - else - { - m_playPos[m_playMode].setTact( 0 ); - m_playPos[m_playMode].setTact64th( 0 ); - } - - m_playPos[m_playMode].setCurrentFrame( 0 ); - updateTimeLinePosition(); - - // remove all note-play-handles that are active - engine::getMixer()->clear(); - - break; - } - - case ACT_PLAY_SONG: - m_playMode = PLAY_SONG; - m_playing = TRUE; - break; - - case ACT_PLAY_TRACK: - m_playMode = PLAY_TRACK; - m_playing = TRUE; - break; - - case ACT_PLAY_BB: - m_playMode = PLAY_BB; - m_playing = TRUE; - break; - - case ACT_PLAY_PATTERN: - m_playMode = PLAY_PATTERN; - m_playing = TRUE; - break; - - case ACT_PAUSE: - m_playing = FALSE;// just set the play-flag - m_paused = TRUE; - break; - - case ACT_RESUME_FROM_PAUSE: - m_playing = TRUE;// just set the play-flag - m_paused = FALSE; - break; - } - - // a second switch for saving pos when starting to play - // anything (need pos for restoring it later in certain - // timeline-modes) - switch( m_actions.front() ) - { - case ACT_PLAY_SONG: - case ACT_PLAY_TRACK: - case ACT_PLAY_BB: - case ACT_PLAY_PATTERN: - { - timeLine * tl = - m_playPos[m_playMode].m_timeLine; - if( tl != NULL ) - { - tl->savePos( m_playPos[m_playMode] ); - } - break; - } - - // keep GCC happy... - default: - break; - } - - m_actions.erase( m_actions.begin() ); - - } - -} - - - - -void songEditor::processNextBuffer( void ) -{ - doActions(); - - if( m_playing == FALSE ) - { - return; - } - - QList trackList; - Sint16 tco_num = -1; - - switch( m_playMode ) - { - case PLAY_SONG: - trackList = tracks(); - // at song-start we have to reset the LFOs - if( m_playPos[PLAY_SONG] == 0 ) - { - envelopeAndLFOWidget::resetLFO(); - } - break; - - case PLAY_TRACK: - trackList.push_back( m_trackToPlay ); - break; - - case PLAY_BB: - if( engine::getBBEditor()->numOfBBs() > 0 ) - { - tco_num = engine::getBBEditor()->currentBB(); - trackList.push_back( bbTrack::findBBTrack( - tco_num ) ); - } - break; - - case PLAY_PATTERN: - if( m_patternToPlay != NULL ) - { - tco_num = m_patternToPlay->getTrack()->getTCONum( - m_patternToPlay ); - trackList.push_back( - m_patternToPlay->getTrack() ); - } - break; - - default: - return; - - } - - if( trackList.empty() == TRUE ) - { - return; - } - - // check for looping-mode and act if neccessary - timeLine * tl = m_playPos[m_playMode].m_timeLine; - bool check_loop = tl != NULL && m_exporting == FALSE && - tl->loopPointsEnabled() && - !( m_playMode == PLAY_PATTERN && - m_patternToPlay->freezing() == TRUE ); - if( check_loop ) - { - if( m_playPos[m_playMode] < tl->loopBegin() || - m_playPos[m_playMode] >= tl->loopEnd() ) - { - m_playPos[m_playMode].setTact( - tl->loopBegin().getTact() ); - m_playPos[m_playMode].setTact64th( - tl->loopBegin().getTact64th() ); - } - } - - f_cnt_t total_frames_played = 0; - float frames_per_tact64th = engine::framesPerTact64th(); - - while( total_frames_played - < engine::getMixer()->framesPerPeriod() ) - { - f_cnt_t played_frames = engine::getMixer() - ->framesPerPeriod() - total_frames_played; - - float current_frame = m_playPos[m_playMode].currentFrame(); - // did we play a 64th of a tact? - if( current_frame >= frames_per_tact64th ) - { - int tact64th = m_playPos[m_playMode].getTact64th() - + (int)( current_frame / frames_per_tact64th ); - // did we play a whole tact? - if( tact64th >= 64 ) - { - // per default we just continue playing even if - // there's no more stuff to play - // (song-play-mode) - int max_tact = m_playPos[m_playMode].getTact() - + 2; - - // then decide whether to go over to next tact - // or to loop back to first tact - if( m_playMode == PLAY_BB ) - { - max_tact = engine::getBBEditor() - ->lengthOfCurrentBB(); - } - else if( m_playMode == PLAY_PATTERN && - m_loopPattern == TRUE && - tl != NULL && - tl->loopPointsEnabled() == FALSE ) - { - max_tact = m_patternToPlay->length() - .getTact(); - } - if( m_playPos[m_playMode].getTact() + 1 - < max_tact ) - { - // next tact - m_playPos[m_playMode].setTact( - m_playPos[m_playMode].getTact() - + 1 ); - } - else - { - // first tact - m_playPos[m_playMode].setTact( 0 ); - } - } - m_playPos[m_playMode].setTact64th( tact64th % 64 ); - - if( check_loop ) - { - if( m_playPos[m_playMode] >= tl->loopEnd() ) - { - m_playPos[m_playMode].setTact( - tl->loopBegin().getTact() ); - m_playPos[m_playMode].setTact64th( - tl->loopBegin().getTact64th() ); - } - } - - current_frame = fmodf( current_frame, - frames_per_tact64th ); - m_playPos[m_playMode].setCurrentFrame( current_frame ); - } - - f_cnt_t last_frames = (f_cnt_t)frames_per_tact64th - - (f_cnt_t)current_frame; - // skip last frame fraction - if( last_frames == 0 ) - { - ++total_frames_played; - m_playPos[m_playMode].setCurrentFrame( current_frame - + 1.0f ); - continue; - } - // do we have some samples left in this tact64th but this are - // less then samples we have to play? - if( last_frames < played_frames ) - { - // then set played_samples to remaining samples, the - // rest will be played in next loop - played_frames = last_frames; - } - - if( (f_cnt_t)current_frame == 0 ) - { - if( m_playMode == PLAY_SONG ) - { - m_automationTrack->play( m_playPos[m_playMode], - played_frames, - total_frames_played, tco_num ); - } - - // loop through all tracks and play them - for( int i = 0; i < trackList.size(); ++i ) - { - trackList[i]->play( m_playPos[m_playMode], - played_frames, - total_frames_played, tco_num ); - } - } - - // update frame-counters - total_frames_played += played_frames; - m_playPos[m_playMode].setCurrentFrame( played_frames + - current_frame ); - } - - if( m_exporting == FALSE ) - { - updateTimeLinePosition(); - } -} - - - - -bool songEditor::realTimeTask( void ) const -{ - return( !( m_exporting == TRUE || ( m_playMode == PLAY_PATTERN && - m_patternToPlay != NULL && - m_patternToPlay->freezing() == TRUE ) ) ); -} - - - - -void songEditor::play( void ) -{ - if( m_playing == TRUE ) - { - if( m_playMode != PLAY_SONG ) - { - // make sure, bb-editor updates/resets it play-button - engine::getBBEditor()->stop(); - //pianoRoll::inst()->stop(); - } - else - { - pause(); - return; - } - } - m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); - m_actions.push_back( ACT_PLAY_SONG ); -} - - - - -void songEditor::playTrack( track * _trackToPlay ) -{ - if( m_playing == TRUE ) - { - stop(); - } - m_trackToPlay = _trackToPlay; - - m_actions.push_back( ACT_PLAY_TRACK ); -} - - - - -void songEditor::playBB( void ) -{ - if( m_playing == TRUE ) - { - stop(); - } - m_actions.push_back( ACT_PLAY_BB ); -} - - - - -void songEditor::playPattern( pattern * _patternToPlay, bool _loop ) -{ - if( m_playing == TRUE ) - { - stop(); - } - m_patternToPlay = _patternToPlay; - m_loopPattern = _loop; - if( m_patternToPlay != NULL ) - { - m_actions.push_back( ACT_PLAY_PATTERN ); - } -} - - - - -tact songEditor::lengthInTacts( void ) const -{ - tact len = 0; - const QList ctl = tracks(); - for( int i = 0; i < ctl.size(); ++i ) - { - len = tMax( ctl[i]->length(), len ); - } - return( len ); -} - - - - -void songEditor::setPlayPos( tact _tact_num, tact64th _t_64th, playModes - _play_mode ) -{ - m_playPos[_play_mode].setTact( _tact_num ); - m_playPos[_play_mode].setTact64th( _t_64th ); - m_playPos[_play_mode].setCurrentFrame( 0.0f ); - if( _play_mode == m_playMode ) - { - updateTimeLinePosition(); - } -} - - - - void songEditor::updateTimeLinePosition( void ) { - if( m_playPos[m_playMode].m_timeLine != NULL && - m_playPos[m_playMode].m_timeLineUpdate == TRUE ) + if( m_s->m_playPos[m_s->m_playMode].m_timeLine != NULL && + m_s->m_playPos[m_s->m_playMode].m_timeLineUpdate == TRUE ) { /* QTimer::singleShot( 1, m_playPos[m_playMode].m_timeLine, SLOT( updatePosition() ) );*/ @@ -1119,460 +659,6 @@ void songEditor::updateTimeLinePosition( void ) -void songEditor::stop( void ) -{ - m_actions.push_back( ACT_STOP_PLAY ); - m_playButton->setIcon( embed::getIconPixmap( "play" ) ); - m_scrollBack = TRUE; -} - - - - - - -void songEditor::pause( void ) -{ - m_actions.push_back( ACT_PAUSE ); - m_playButton->setIcon( embed::getIconPixmap( "play" ) ); -} - - - - -void songEditor::resumeFromPause( void ) -{ - m_actions.push_back( ACT_RESUME_FROM_PAUSE ); - m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); -} - - - - -void songEditor::startExport( void ) -{ - stop(); - doActions(); - - play(); - doActions(); - - m_exporting = TRUE; -} - - - - -void songEditor::stopExport( void ) -{ - stop(); - m_exporting = FALSE; -} - - - - - - -void songEditor::insertBar( void ) -{ - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - tl[i]->getTrackContentWidget()->insertTact( - m_playPos[PLAY_SONG] ); - } -} - - - - -void songEditor::removeBar( void ) -{ - QList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) - { - tl[i]->getTrackContentWidget()->removeTact( - m_playPos[PLAY_SONG] ); - } -} - - - - -void songEditor::addBBTrack( void ) -{ - track * t = track::create( track::BB_TRACK, this ); - if( dynamic_cast( t ) != NULL ) - { - dynamic_cast( t )->clickedTrackLabel(); - } -} - - - - -void songEditor::addSampleTrack( void ) -{ - (void) track::create( track::SAMPLE_TRACK, this ); -} - - - - -bpm_t songEditor::getTempo( void ) -{ - return( m_tempoModel.value() ); -} - - - - -automationPattern * songEditor::tempoAutomationPattern( void ) -{ - return( m_tempoModel.getAutomationPattern() ); -} - - - - -void songEditor::clearProject( void ) -{ - engine::getProjectJournal()->setJournalling( FALSE ); - - if( m_playing ) - { - stop(); - } - - engine::getMixer()->lock(); - clearAllTracks(); - - engine::getAutomationEditor()->setCurrentPattern( NULL ); - m_tempoModel.getAutomationPattern()->clear(); - m_masterVolumeModel.getAutomationPattern()->clear(); - m_masterPitchModel.getAutomationPattern()->clear(); - - engine::getBBEditor()->clearAllTracks(); - engine::getMixer()->unlock(); - - engine::getProjectNotes()->clear(); - - engine::getProjectJournal()->clearInvalidJournallingObjects(); - engine::getProjectJournal()->clearJournal(); - - engine::getProjectJournal()->setJournalling( TRUE ); -} - - - - - -// create new file -void songEditor::createNewProject( void ) -{ - QString default_template = configManager::inst()->userProjectsDir() - + "templates/default.mpt"; - if( QFile::exists( default_template ) ) - { - createNewProjectFromTemplate( default_template ); - return; - } - - default_template = configManager::inst()->factoryProjectsDir() - + "templates/default.mpt"; - if( QFile::exists( default_template ) ) - { - createNewProjectFromTemplate( default_template ); - return; - } - - m_loadingProject = TRUE; - - clearProject(); - - engine::getProjectJournal()->setJournalling( FALSE ); - - m_fileName = m_oldFileName = ""; - - engine::getMainWindow()->resetWindowTitle(); - - track * t; - t = track::create( track::INSTRUMENT_TRACK, this ); - dynamic_cast< instrumentTrack * >( t )->loadInstrument( - "tripleoscillator" ); - track::create( track::SAMPLE_TRACK, this ); - t = track::create( track::INSTRUMENT_TRACK, engine::getBBEditor() ); - dynamic_cast< instrumentTrack * >( t )->loadInstrument( - "tripleoscillator" ); - track::create( track::BB_TRACK, this ); - - m_tempoModel.setInitValue( DEFAULT_BPM ); - m_masterVolumeModel.setInitValue( 100 ); - m_masterPitchModel.setInitValue( 0 ); - - engine::getProjectJournal()->setJournalling( TRUE ); - - m_loadingProject = FALSE; -} - - - - -void FASTCALL songEditor::createNewProjectFromTemplate( const QString & - _template ) -{ - loadProject( _template ); - // clear file-name so that user doesn't overwrite template when - // saving... - m_fileName = m_oldFileName = ""; -} - - - - -// load given song -void FASTCALL songEditor::loadProject( const QString & _file_name ) -{ - m_loadingProject = TRUE; - - clearProject(); - - engine::getProjectJournal()->setJournalling( FALSE ); - - m_fileName = _file_name; - m_oldFileName = _file_name; - - multimediaProject mmp( m_fileName ); - // if file could not be opened, head-node is null and we create - // new project - if( mmp.head().isNull() ) - { - createNewProject(); - return; - } - - engine::getMainWindow()->resetWindowTitle(); - - // get the header information from the DOM - m_tempoModel.loadSettings( mmp.head(), "bpm" ); - m_masterVolumeModel.loadSettings( mmp.head(), "mastervol" ); - m_masterPitchModel.loadSettings( mmp.head(), "masterpitch" ); - - // reset loop-point-state - m_playPos[PLAY_SONG].m_timeLine->toggleLoopPoints( 0 ); - - QDomNode node = mmp.content().firstChild(); - while( !node.isNull() ) - { - if( node.isElement() ) - { - if( node.nodeName() == "trackcontainer" ) - { - ( (journallingObject *)( this ) )-> - restoreState( node.toElement() ); - } - else if( node.nodeName() == - engine::getPianoRoll()->nodeName() ) - { - engine::getPianoRoll()->restoreState( - node.toElement() ); - } - else if( node.nodeName() == - engine::getAutomationEditor()->nodeName() ) - { - engine::getAutomationEditor()->restoreState( - node.toElement() ); - } - else if( node.nodeName() == - engine::getProjectNotes()->nodeName() ) - { - ( (journallingObject *)( engine:: - getProjectNotes() ) )-> - restoreState( node.toElement() ); - } - else if( node.nodeName() == - m_playPos[PLAY_SONG].m_timeLine->nodeName() ) - { - m_playPos[PLAY_SONG].m_timeLine->restoreState( - node.toElement() ); - } - } - node = node.nextSibling(); - } - - m_leftRightScroll->setValue( 0 ); - - configManager::inst()->addRecentlyOpenedProject( _file_name ); - - engine::getProjectJournal()->setJournalling( TRUE ); - - m_loadingProject = FALSE; -} - - - - -// save current song -bool songEditor::saveProject( void ) -{ - multimediaProject mmp( multimediaProject::SONG_PROJECT ); - - m_tempoModel.saveSettings( mmp, mmp.head(), "bpm" ); - m_masterVolumeModel.saveSettings( mmp, mmp.head(), "mastervol" ); - m_masterPitchModel.saveSettings( mmp, mmp.head(), "masterpitch" ); - - - ( (journallingObject *)( this ) )->saveState( mmp, mmp.content() ); - - engine::getPianoRoll()->saveState( mmp, mmp.content() ); - engine::getAutomationEditor()->saveState( mmp, mmp.content() ); - ( (journallingObject *)( engine::getProjectNotes() ) )->saveState( mmp, - mmp.content() ); - m_playPos[PLAY_SONG].m_timeLine->saveState( mmp, mmp.content() ); - - m_fileName = mmp.nameWithExtension( m_fileName ); - if( mmp.writeFile( m_fileName, m_oldFileName == "" || - m_fileName != m_oldFileName ) == TRUE ) - { - textFloat::displayMessage( tr( "Project saved" ), - tr( "The project %1 is now saved." - ).arg( m_fileName ), - embed::getIconPixmap( "project_save", 24, 24 ), - 2000 ); - configManager::inst()->addRecentlyOpenedProject( m_fileName ); - engine::getMainWindow()->resetWindowTitle(); - } - else - { - textFloat::displayMessage( tr( "Project NOT saved." ), - tr( "The project %1 was not saved!" ).arg( - m_fileName ), - embed::getIconPixmap( "error" ), 4000 ); - return( FALSE ); - } - return( TRUE ); -} - - - - -// save current song in given filename -bool FASTCALL songEditor::saveProjectAs( const QString & _file_name ) -{ - QString o = m_oldFileName; - m_oldFileName = m_fileName; - m_fileName = _file_name; - if( saveProject() == FALSE ) - { - m_fileName = m_oldFileName; - m_oldFileName = o; - return( FALSE ); - } - m_oldFileName = m_fileName; - return( TRUE ); -} - - - - -void songEditor::importProject( void ) -{ - QFileDialog ofd( this, tr( "Import file" ), ""/*, - tr( "MIDI-files (*.mid)" )*/ ); - ofd.setDirectory( configManager::inst()->userProjectsDir() ); - ofd.setFileMode( QFileDialog::ExistingFiles ); - if( ofd.exec () == QDialog::Accepted && !ofd.selectedFiles().isEmpty() ) - { - importFilter::import( ofd.selectedFiles()[0], this ); - } -} - - -#warning TODO: move somewhere else -static inline QString baseName( const QString & _file ) -{ - return( QFileInfo( _file ).absolutePath() + "/" + - QFileInfo( _file ).completeBaseName() ); -} - - -void songEditor::exportProject( void ) -{ - QString base_filename; - - if( m_fileName != "" ) - { - base_filename = baseName( m_fileName ); - } - else - { - base_filename = tr( "untitled" ); - } - base_filename += fileEncodeDevices[0].m_extension; - - QFileDialog efd( engine::getMainWindow() ); - efd.setFileMode( QFileDialog::AnyFile ); - - int idx = 0; - QStringList types; - while( fileEncodeDevices[idx].m_fileType != NULL_FILE ) - { - types << tr( fileEncodeDevices[idx].m_description ); - ++idx; - } - efd.setFilters( types ); - efd.selectFile( base_filename ); - efd.setWindowTitle( tr( "Select file for project-export..." ) ); - - if( efd.exec() == QDialog::Accepted && - !efd.selectedFiles().isEmpty() && efd.selectedFiles()[0] != "" - ) - { - const QString export_file_name = efd.selectedFiles()[0]; - if( QFileInfo( export_file_name ).exists() == TRUE && - QMessageBox::warning( engine::getMainWindow(), - tr( "File already exists" ), - tr( "The file \"%1\" already " - "exists. Do you want " - "to overwrite it?" - ).arg( QFileInfo( - export_file_name ).fileName() ), - QMessageBox::Yes, - QMessageBox::No | - QMessageBox::Escape | - QMessageBox::Default ) - == QMessageBox::No ) - { - return; - } - exportProjectDialog epd( export_file_name, - engine::getMainWindow() ); - epd.exec(); - } -} - - - - -void songEditor::updateFramesPerTact64th( void ) -{ - engine::updateFramesPerTact64th(); -} - - - - -void songEditor::setModified( void ) -{ - if( !m_loadingProject ) - { - engine::getMainWindow()->resetWindowTitle( TRUE ); - } -} - - - bool songEditor::allowRubberband( void ) const { diff --git a/src/core/timeline.cpp b/src/core/timeline.cpp index abf735e977..53afba87b1 100644 --- a/src/core/timeline.cpp +++ b/src/core/timeline.cpp @@ -51,12 +51,12 @@ QPixmap * timeLine::s_loopPointDisabledPixmap = NULL; timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt, - songEditor::playPos & _pos, const midiTime & _begin, + song::playPos & _pos, const midiTime & _begin, QWidget * _parent ) : QWidget( _parent ), - m_autoScroll( AUTOSCROLL_ENABLED ), - m_loopPoints( LOOP_POINTS_DISABLED ), - m_behaviourAtStop( BACK_TO_ZERO ), + m_autoScroll( AutoScrollEnabled ), + m_loopPoints( LoopPointsDisabled ), + m_behaviourAtStop( BackToZero ), m_changedPosition( TRUE ), m_xOffset( _xoff ), m_posMarkerX( 0 ), @@ -65,7 +65,7 @@ timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt, m_begin( _begin ), m_savedPos( -1 ), m_hint( NULL ), - m_action( NONE ), + m_action( NoAction ), m_moveXOff( 0 ) { m_loopPos[0] = 0; @@ -175,7 +175,7 @@ void timeLine::loadSettings( const QDomElement & _this ) { m_loopPos[0] = _this.attribute( "lp0pos" ).toInt(); m_loopPos[1] = _this.attribute( "lp1pos" ).toInt(); - m_loopPoints = static_cast( + m_loopPoints = static_cast( _this.attribute( "lpstate" ).toInt() ); update(); emit loopPointStateLoaded( m_loopPoints ); @@ -192,7 +192,7 @@ void timeLine::updatePosition( const midiTime & ) { m_posMarkerX = new_x; m_changedPosition = TRUE; - if( m_autoScroll == AUTOSCROLL_ENABLED ) + if( m_autoScroll == AutoScrollEnabled ) { emit positionChanged( m_pos ); } @@ -205,7 +205,7 @@ void timeLine::updatePosition( const midiTime & ) void timeLine::toggleAutoScroll( int _n ) { - m_autoScroll = static_cast( _n ); + m_autoScroll = static_cast( _n ); } @@ -213,7 +213,7 @@ void timeLine::toggleAutoScroll( int _n ) void timeLine::toggleLoopPoints( int _n ) { - m_loopPoints = static_cast( _n ); + m_loopPoints = static_cast( _n ); update(); } @@ -222,7 +222,7 @@ void timeLine::toggleLoopPoints( int _n ) void timeLine::toggleBehaviourAtStop( int _n ) { - m_behaviourAtStop = static_cast( _n ); + m_behaviourAtStop = static_cast( _n ); } @@ -280,7 +280,7 @@ void timeLine::mousePressEvent( QMouseEvent * _me ) } if( _me->button() == Qt::LeftButton ) { - m_action = MOVE_POS_MARKER; + m_action = MovePositionMarker; if( _me->x() - m_xOffset < s_posMarkerPixmap->width() ) { m_moveXOff = _me->x() - m_xOffset; @@ -294,18 +294,18 @@ void timeLine::mousePressEvent( QMouseEvent * _me ) { const midiTime t = m_begin + static_cast( _me->x() * 64 / m_ppt ); - m_action = MOVE_LOOP_BEGIN; + m_action = MoveLoopBegin; if( m_loopPos[0] > m_loopPos[1] ) { qSwap( m_loopPos[0], m_loopPos[1] ); } if( _me->button() == Qt::RightButton ) { - m_action = MOVE_LOOP_END; + m_action = MoveLoopEnd; } - m_loopPos[( m_action == MOVE_LOOP_BEGIN ) ? 0 : 1] = t; + m_loopPos[( m_action == MoveLoopBegin ) ? 0 : 1] = t; } - if( m_action == MOVE_LOOP_BEGIN || m_action == MOVE_LOOP_END ) + if( m_action == MoveLoopBegin || m_action == MoveLoopEnd ) { delete m_hint; m_hint = textFloat::displayMessage( tr( "Hint" ), @@ -325,17 +325,17 @@ void timeLine::mouseMoveEvent( QMouseEvent * _me ) m_xOffset - m_moveXOff, 0 ) * 64 / m_ppt ); switch( m_action ) { - case MOVE_POS_MARKER: + case MovePositionMarker: m_pos.setTact( t.getTact() ); m_pos.setTact64th( t.getTact64th() ); m_pos.setCurrentFrame( 0 ); updatePosition(); break; - case MOVE_LOOP_BEGIN: - case MOVE_LOOP_END: + case MoveLoopBegin: + case MoveLoopEnd: { - const Uint8 i = m_action - MOVE_LOOP_BEGIN; + const Uint8 i = m_action - MoveLoopBegin; if( engine::getMainWindow()->isCtrlPressed() == TRUE ) { // no ctrl-press-hint when having ctrl pressed @@ -363,7 +363,7 @@ void timeLine::mouseReleaseEvent( QMouseEvent * _me ) { delete m_hint; m_hint = NULL; - m_action = NONE; + m_action = NoAction; } diff --git a/src/core/track.cpp b/src/core/track.cpp index 7d4d916167..575c21f5e8 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -4,7 +4,7 @@ * track.cpp - implementation of classes concerning tracks -> neccessary for * all track-like objects (beat/bassline, sample-track...) * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -28,15 +28,16 @@ #include "track.h" +#include -#include #include #include #include +#include #include -#include "automation_pattern.h" +//#include "automation_pattern.h" #include "automation_track.h" #include "bb_editor.h" #include "bb_track.h" @@ -50,7 +51,7 @@ #include "pixmap_button.h" #include "project_journal.h" #include "sample_track.h" -#include "song_editor.h" +#include "song.h" #include "string_pair_drag.h" #include "templates.h" #include "text_float.h" @@ -66,21 +67,138 @@ const Uint16 TRACK_OP_BTN_HEIGHT = 14; const Uint16 MINIMAL_TRACK_HEIGHT = 32; -textFloat * trackContentObject::s_textFloat = NULL; +textFloat * trackContentObjectView::s_textFloat = NULL; // =========================================================================== // trackContentObject // =========================================================================== trackContentObject::trackContentObject( track * _track ) : - selectableObject( _track->getTrackContentWidget() ), + model( _track ), m_track( _track ), m_startPosition(), m_length(), - m_action( NONE ), + m_mutedModel( FALSE, this ) +{ + setJournalling( FALSE ); + movePosition( 0 ); + changeLength( 0 ); + setJournalling( TRUE ); +} + + + + +trackContentObject::~trackContentObject() +{ + m_track->removeTCO( this ); +} + + + + +void trackContentObject::movePosition( const midiTime & _pos ) +{ + if( m_startPosition != _pos ) + { + addJournalEntry( journalEntry( Move, m_startPosition - _pos ) ); + m_startPosition = _pos; + } + emit positionChanged(); +} + + + + +void trackContentObject::changeLength( const midiTime & _length ) +{ + if( m_length != _length ) + { + addJournalEntry( journalEntry( Resize, m_length - _length ) ); + m_length = _length; + } + emit lengthChanged(); +} + + + + +void trackContentObject::undoStep( journalEntry & _je ) +{ + saveJournallingState( FALSE ); + switch( _je.actionID() ) + { + case Move: + movePosition( startPosition() + _je.data().toInt() ); + break; + case Resize: + changeLength( length() + _je.data().toInt() ); + break; + } + restoreJournallingState(); +} + + + + +void trackContentObject::redoStep( journalEntry & _je ) +{ + journalEntry je( _je.actionID(), -_je.data().toInt() ); + undoStep( je ); +} + + + + +void trackContentObject::cut( void ) +{ + copy(); + deleteLater(); +} + + + + +void trackContentObject::copy( void ) +{ + clipboard::copy( this ); +} + + + + +void trackContentObject::paste( void ) +{ + if( clipboard::getContent( nodeName() ) != NULL ) + { + restoreState( *( clipboard::getContent( nodeName() ) ) ); + } +} + + + + +void trackContentObject::toggleMute( void ) +{ + m_mutedModel.setValue( !m_mutedModel.value() ); + emit dataChanged(); +} + + + + + + + +trackContentObjectView::trackContentObjectView( trackContentObject * _tco, + trackView * _tv ) : + selectableObject( _tv->getTrackContentWidget() ), + modelView( NULL ), + m_tco( _tco ), + m_trackView( _tv ), + m_action( NoAction ), m_autoResize( FALSE ), m_initialMouseX( 0 ), - m_muted( FALSE ), m_hint( NULL ) { if( s_textFloat == NULL ) @@ -91,55 +209,58 @@ trackContentObject::trackContentObject( track * _track ) : setAttribute( Qt::WA_DeleteOnClose ); setFocusPolicy( Qt::StrongFocus ); + move( 0, 1 ); show(); - setJournalling( FALSE ); - movePosition( 0 ); - changeLength( 0 ); - setJournalling( TRUE ); - - setFixedHeight( parentWidget()->height() - 2 ); + setFixedHeight( _tv->getTrackContentWidget()->height() - 2 ); setAcceptDrops( TRUE ); setMouseTracking( TRUE ); + + connect( m_tco, SIGNAL( lengthChanged() ), + this, SLOT( updateLength() ) ); + connect( m_tco, SIGNAL( positionChanged() ), + this, SLOT( updatePosition() ) ); + connect( m_tco, SIGNAL( destroyed( QObject * ) ), + this, SLOT( close() ), Qt::QueuedConnection ); + setModel( m_tco ); + + m_trackView->getTrackContentWidget()->addTCOView( this ); } -trackContentObject::~trackContentObject() +trackContentObjectView::~trackContentObjectView() { delete m_hint; + // we have to give our track-container the focus because otherwise the + // op-buttons of our track-widgets could become focus and when the user + // presses space for playing song, just one of these buttons is pressed + // which results in unwanted effects + m_trackView->getTrackContainerView()->setFocus(); } -bool trackContentObject::fixedTCOs( void ) +bool trackContentObjectView::fixedTCOs( void ) { - return( m_track->getTrackContainer()->fixedTCOs() ); + return( m_trackView->getTrackContainerView()->fixedTCOs() ); } -void trackContentObject::movePosition( const midiTime & _pos ) +bool trackContentObjectView::close( void ) { - if( m_startPosition != _pos ) - { - //engine::getSongEditor()->setModified(); - addJournalEntry( journalEntry( MOVE, m_startPosition - _pos ) ); - m_startPosition = _pos; - } - m_track->getTrackWidget()->changePosition(); - // moving a TCO can result in change of song-length etc., - // therefore we update the track-container - m_track->getTrackContainer()->update(); + m_trackView->getTrackContentWidget()->removeTCOView( this ); + QWidget::close(); } -void trackContentObject::changeLength( const midiTime & _length ) +void trackContentObjectView::updateLength( void ) { if( fixedTCOs() ) { @@ -147,48 +268,49 @@ void trackContentObject::changeLength( const midiTime & _length ) } else { - setFixedWidth( static_cast( m_length * pixelsPerTact() / + setFixedWidth( static_cast( m_tco->length() * + pixelsPerTact() / 64 ) + TCO_BORDER_WIDTH * 2 ); } - - if( m_length != _length ) - { - //engine::getSongEditor()->setModified(); - addJournalEntry( journalEntry( RESIZE, m_length - _length ) ); - m_length = _length; - - // changing length of TCO can result in change of song-length - // etc., therefore we update the track-container - m_track->getTrackContainer()->update(); - } + m_trackView->getTrackContainerView()->update(); } -void trackContentObject::dragEnterEvent( QDragEnterEvent * _dee ) +void trackContentObjectView::updatePosition( void ) +{ + m_trackView->getTrackContentWidget()->changePosition(); + // moving a TCO can result in change of song-length etc., + // therefore we update the track-container + m_trackView->getTrackContainerView()->update(); +} + + + +void trackContentObjectView::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, "tco_" + - QString::number( m_track->type() ) ); + QString::number( m_tco->getTrack()->type() ) ); } -void trackContentObject::dropEvent( QDropEvent * _de ) +void trackContentObjectView::dropEvent( QDropEvent * _de ) { QString type = stringPairDrag::decodeKey( _de ); QString value = stringPairDrag::decodeValue( _de ); - if( type == ( "tco_" + QString::number( m_track->type() ) ) ) + if( type == ( "tco_" + QString::number( m_tco->getTrack()->type() ) ) ) { // value contains our XML-data so simply create a // multimediaProject which does the rest for us... multimediaProject mmp( value, FALSE ); // at least save position before getting to moved to somewhere // the user doesn't expect... - midiTime pos = startPosition(); - restoreState( mmp.content().firstChild().toElement() ); - movePosition( pos ); + midiTime pos = m_tco->startPosition(); + m_tco->restoreState( mmp.content().firstChild().toElement() ); + m_tco->movePosition( pos ); _de->accept(); } } @@ -196,7 +318,7 @@ void trackContentObject::dropEvent( QDropEvent * _de ) -void trackContentObject::leaveEvent( QEvent * _e ) +void trackContentObjectView::leaveEvent( QEvent * _e ) { while( QApplication::overrideCursor() != NULL ) { @@ -211,13 +333,13 @@ void trackContentObject::leaveEvent( QEvent * _e ) -void trackContentObject::mousePressEvent( QMouseEvent * _me ) +void trackContentObjectView::mousePressEvent( QMouseEvent * _me ) { - if( m_track->getTrackContainer()->allowRubberband() == TRUE && + if( m_trackView->getTrackContainerView()->allowRubberband() == TRUE && _me->button() == Qt::LeftButton ) { // if rubberband is active, we can be selected - if( m_track->getTrackContainer()->rubberBandActive() == FALSE ) + if( !m_trackView->getTrackContainerView()->rubberBandActive() ) { if( engine::getMainWindow()->isCtrlPressed() == TRUE ) { @@ -225,7 +347,7 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) } else if( isSelected() == TRUE ) { - m_action = MOVE_SELECTION; + m_action = MoveSelection; m_initialMouseX = _me->x(); } } @@ -244,13 +366,14 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) engine::getMainWindow()->isCtrlPressed() == TRUE ) { // start drag-action - multimediaProject mmp( multimediaProject::DRAG_N_DROP_DATA ); - saveState( mmp, mmp.content() ); + multimediaProject mmp( multimediaProject::DragNDropData ); + m_tco->saveState( mmp, mmp.content() ); QPixmap thumbnail = QPixmap::grabWidget( this ).scaled( 128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation ); - new stringPairDrag( QString( "tco_%1" ).arg( m_track->type() ), + new stringPairDrag( QString( "tco_%1" ).arg( + m_tco->getTrack()->type() ), mmp.toString(), thumbnail, this ); } else if( _me->button() == Qt::LeftButton && @@ -258,14 +381,14 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) fixedTCOs() == FALSE ) { // move or resize - setJournalling( FALSE ); + m_tco->setJournalling( FALSE ); m_initialMouseX = _me->x(); if( _me->x() < width() - RESIZE_GRIP_WIDTH ) { - m_action = MOVE; - m_oldTime = m_startPosition; + m_action = Move; + m_oldTime = m_tco->startPosition(); QCursor c( Qt::SizeAllCursor ); QApplication::setOverrideCursor( c ); s_textFloat->setTitle( tr( "Current position" ) ); @@ -277,8 +400,8 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) } else if( m_autoResize == FALSE ) { - m_action = RESIZE; - m_oldTime = m_length; + m_action = Resize; + m_oldTime = m_tco->length(); QCursor c( Qt::SizeHorCursor ); QApplication::setOverrideCursor( c ); s_textFloat->setTitle( tr( "Current length" ) ); @@ -297,12 +420,14 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) { if( engine::getMainWindow()->isCtrlPressed() ) { - toggleMute(); + m_tco->toggleMute(); } else if( fixedTCOs() == FALSE ) { // delete ourself - close(); + m_trackView->getTrackContentWidget()-> + removeTCOView( this ); + m_tco->deleteLater(); } } } @@ -310,7 +435,7 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) -void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) +void trackContentObjectView::mouseMoveEvent( QMouseEvent * _me ) { if( engine::getMainWindow()->isCtrlPressed() == TRUE ) { @@ -318,31 +443,32 @@ void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) m_hint = NULL; } - const float ppt = m_track->getTrackContainer()->pixelsPerTact(); - if( m_action == MOVE ) + const float ppt = m_trackView->getTrackContainerView()->pixelsPerTact(); + if( m_action == Move ) { const int x = mapToParent( _me->pos() ).x() - m_initialMouseX; - midiTime t = tMax( 0, (Sint32) m_track->getTrackContainer()-> - currentPosition() + + midiTime t = tMax( 0, (Sint32) + m_trackView->getTrackContainerView()->currentPosition()+ static_cast( x * 64 / ppt ) ); if( engine::getMainWindow()->isCtrlPressed() == FALSE && _me->button() == Qt::NoButton ) { t = t.toNearestTact(); } - movePosition( t ); - m_track->getTrackWidget()->changePosition(); + m_tco->movePosition( t ); + m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). - arg( m_startPosition.getTact() + 1 ). - arg( m_startPosition.getTact64th() ) ); - s_textFloat->move( QPoint(8, s_textFloat->parentWidget()->height() - + arg( m_tco->startPosition().getTact() + 1 ). + arg( m_tco->startPosition().getTact64th() ) ); + s_textFloat->move( QPoint( 8, + s_textFloat->parentWidget()->height() - s_textFloat->height() - 24 ) ); } - else if( m_action == MOVE_SELECTION ) + else if( m_action == MoveSelection ) { const int dx = _me->x() - m_initialMouseX; QVector so = - m_track->getTrackContainer()->selectedObjects(); + m_trackView->getTrackContainerView()->selectedObjects(); QVector tcos; midiTime smallest_pos; // find out smallest position of all selected objects for not @@ -369,7 +495,7 @@ void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) smallest_pos ); } } - else if( m_action == RESIZE ) + else if( m_action == Resize ) { midiTime t = tMax( 64, static_cast( _me->x() * 64 / ppt ) ); @@ -378,14 +504,14 @@ void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) { t = t.toNearestTact(); } - changeLength( t ); + m_tco->changeLength( t ); s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). - arg( length().getTact() ). - arg( length().getTact64th() ). - arg( m_startPosition.getTact() + 1 ). - arg( m_startPosition.getTact64th() ). - arg( endPosition().getTact() + 1 ). - arg( endPosition().getTact64th() ) ); + arg( m_tco->length().getTact() ). + arg( m_tco->length().getTact64th() ). + arg( m_tco->startPosition().getTact() + 1 ). + arg( m_tco->startPosition().getTact64th() ). + arg( m_tco->endPosition().getTact() + 1 ). + arg( m_tco->endPosition().getTact64th() ) ); s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) + QPoint( width() + 2, 8 ) ); } @@ -415,16 +541,16 @@ void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) -void trackContentObject::mouseReleaseEvent( QMouseEvent * _me ) +void trackContentObjectView::mouseReleaseEvent( QMouseEvent * _me ) { - if( m_action == MOVE || m_action == RESIZE ) + if( m_action == Move || m_action == Resize ) { - setJournalling( TRUE ); - addJournalEntry( journalEntry( m_action, m_oldTime - - ( ( m_action == MOVE ) ? - m_startPosition : m_length ) ) ); + m_tco->setJournalling( TRUE ); + m_tco->addJournalEntry( journalEntry( m_action, m_oldTime - + ( ( m_action == Move ) ? + m_tco->startPosition() : m_tco->length() ) ) ); } - m_action = NONE; + m_action = NoAction; delete m_hint; m_hint = NULL; s_textFloat->hide(); @@ -435,26 +561,26 @@ void trackContentObject::mouseReleaseEvent( QMouseEvent * _me ) -void trackContentObject::contextMenuEvent( QContextMenuEvent * _cme ) +void trackContentObjectView::contextMenuEvent( QContextMenuEvent * _cme ) { QMenu contextMenu( this ); if( fixedTCOs() == FALSE ) { contextMenu.addAction( embed::getIconPixmap( "cancel" ), tr( "Delete (middle mousebutton)" ), - this, SLOT( close() ) ); + m_tco, SLOT( deleteLater() ) ); contextMenu.addSeparator(); contextMenu.addAction( embed::getIconPixmap( "edit_cut" ), - tr( "Cut" ), this, SLOT( cut() ) ); + tr( "Cut" ), m_tco, SLOT( cut() ) ); } contextMenu.addAction( embed::getIconPixmap( "edit_copy" ), - tr( "Copy" ), this, SLOT( copy() ) ); + tr( "Copy" ), m_tco, SLOT( copy() ) ); contextMenu.addAction( embed::getIconPixmap( "edit_paste" ), - tr( "Paste" ), this, SLOT( paste() ) ); + tr( "Paste" ), m_tco, SLOT( paste() ) ); contextMenu.addSeparator(); contextMenu.addAction( embed::getIconPixmap( "muted" ), tr( "Mute/unmute ( + middle click)" ), - this, SLOT( toggleMute() ) ); + m_tco, SLOT( toggleMute() ) ); constructContextMenu( &contextMenu ); contextMenu.exec( QCursor::pos() ); @@ -463,93 +589,15 @@ void trackContentObject::contextMenuEvent( QContextMenuEvent * _cme ) -float trackContentObject::pixelsPerTact( void ) +float trackContentObjectView::pixelsPerTact( void ) { - return( getTrack()->getTrackContainer()->pixelsPerTact() ); + return( m_trackView->getTrackContainerView()->pixelsPerTact() ); } -void trackContentObject::undoStep( journalEntry & _je ) -{ - saveJournallingState( FALSE ); - switch( _je.actionID() ) - { - case MOVE: - movePosition( startPosition() + _je.data().toInt() ); - break; - case RESIZE: - changeLength( length() + _je.data().toInt() ); - break; - } - restoreJournallingState(); -} - - - - -void trackContentObject::redoStep( journalEntry & _je ) -{ - journalEntry je( _je.actionID(), -_je.data().toInt() ); - undoStep( je ); -} - - - - -void trackContentObject::close( void ) -{ - m_track->getTrackContentWidget()->removeTCO( this, FALSE ); - // we have to give our track-container the focus because otherwise the - // op-buttons of our track-widgets could become focus and when the user - // presses space for playing song, just one of these buttons is pressed - // which results in unwanted effects - m_track->getTrackContainer()->setFocus(); - QWidget::close(); -} - - - - -void trackContentObject::cut( void ) -{ - copy(); - close(); -} - - - - -void trackContentObject::copy( void ) -{ - clipboard::copy( this ); -} - - - - -void trackContentObject::paste( void ) -{ - if( clipboard::getContent( nodeName() ) != NULL ) - { - restoreState( *( clipboard::getContent( nodeName() ) ) ); - } -} - - - - -void trackContentObject::toggleMute( void ) -{ - m_muted = !m_muted; - update(); -} - - - - -void trackContentObject::setAutoResizeEnabled( bool _e ) +void trackContentObjectView::setAutoResizeEnabled( bool _e ) { m_autoResize = _e; } @@ -557,18 +605,23 @@ void trackContentObject::setAutoResizeEnabled( bool _e ) + // =========================================================================== // trackContentWidget // =========================================================================== -trackContentWidget::trackContentWidget( trackWidget * _parent ) : +trackContentWidget::trackContentWidget( trackView * _parent ) : QWidget( _parent ), - m_trackWidget( _parent ) + m_trackView( _parent ) { setAutoFillBackground( TRUE ); QPalette pal; pal.setColor( backgroundRole(), QColor( 96, 96, 96 ) ); setPalette( pal ); setAcceptDrops( TRUE ); + + connect( _parent->getTrackContainerView(), + SIGNAL( positionChanged( const midiTime & ) ), + this, SLOT( changePosition( const midiTime & ) ) ); } @@ -581,156 +634,41 @@ trackContentWidget::~trackContentWidget() -trackContentObject * trackContentWidget::getTCO( int _tco_num ) -{ - if( _tco_num < m_trackContentObjects.size() ) - { - return( m_trackContentObjects[_tco_num] ); - } - printf( "called trackContentWidget::getTCO( %d, TRUE ), " - "but TCO %d doesn't exist\n", _tco_num, _tco_num ); - return( getTrack()->addTCO( getTrack()->createTCO( _tco_num * 64 ) ) ); -} - - - - -int trackContentWidget::numOfTCOs( void ) -{ - return( m_trackContentObjects.size() ); -} - - - - -trackContentObject * trackContentWidget::addTCO( trackContentObject * _tco ) +void trackContentWidget::addTCOView( trackContentObjectView * _tcov ) { + trackContentObject * tco = _tcov->getTrackContentObject(); QMap map; - map["id"] = _tco->id(); - addJournalEntry( journalEntry( ADD_TCO, map ) ); + map["id"] = tco->id(); + addJournalEntry( journalEntry( AddTrackContentObject, map ) ); - m_trackContentObjects.push_back( _tco ); - _tco->move( 0, 1 ); + m_tcoViews.push_back( _tcov ); - _tco->saveJournallingState( FALSE ); - m_trackWidget->changePosition(); - _tco->restoreJournallingState(); + tco->saveJournallingState( FALSE ); + changePosition(); + tco->restoreJournallingState(); - //engine::getSongEditor()->setModified(); - return( _tco ); // just for convenience } -void trackContentWidget::removeTCO( int _tco_num, bool _also_delete ) +void trackContentWidget::removeTCOView( trackContentObjectView * _tcov ) { - removeTCO( getTCO( _tco_num ), _also_delete ); -} - - - - -void trackContentWidget::removeTCO( trackContentObject * _tco, - bool _also_delete ) -{ - tcoVector::iterator it = qFind( m_trackContentObjects.begin(), - m_trackContentObjects.end(), - _tco ); - if( it != m_trackContentObjects.end() ) + tcoViewVector::iterator it = qFind( m_tcoViews.begin(), + m_tcoViews.end(), + _tcov ); + if( it != m_tcoViews.end() ) { QMap map; - multimediaProject mmp( multimediaProject::JOURNAL_DATA ); - _tco->saveState( mmp, mmp.content() ); - map["id"] = _tco->id(); + multimediaProject mmp( multimediaProject::JournalData ); + _tcov->getTrackContentObject()->saveState( mmp, mmp.content() ); + map["id"] = _tcov->getTrackContentObject()->id(); map["state"] = mmp.toString(); - addJournalEntry( journalEntry( REMOVE_TCO, map ) ); + addJournalEntry( journalEntry( RemoveTrackContentObject, + map ) ); - if( _also_delete ) - { - delete _tco; - } - - m_trackContentObjects.erase( it ); - engine::getSongEditor()->setModified(); - } -} - - - - -void trackContentWidget::removeAllTCOs( void ) -{ - while( !m_trackContentObjects.empty() ) - { - delete m_trackContentObjects.front(); - m_trackContentObjects.erase( m_trackContentObjects.begin() ); - } -} - - - - -void trackContentWidget::swapPositionOfTCOs( int _tco_num1, int _tco_num2 ) -{ - // TODO: range-checking - qSwap( m_trackContentObjects[_tco_num1], - m_trackContentObjects[_tco_num2] ); - - const midiTime pos = m_trackContentObjects[_tco_num1]->startPosition(); - - m_trackContentObjects[_tco_num1]->movePosition( - m_trackContentObjects[_tco_num2]->startPosition() ); - m_trackContentObjects[_tco_num2]->movePosition( pos ); -} - - - - -tact trackContentWidget::length( void ) const -{ - // find last end-position - midiTime last = 0; - for( tcoVector::const_iterator it = m_trackContentObjects.begin(); - it != m_trackContentObjects.end(); ++it ) - { - last = tMax( ( *it )->endPosition(), last ); - } - return( last.getTact() + ( ( last.getTact64th() != 0 )? 1 : 0 ) ); -} - - - - -void trackContentWidget::insertTact( const midiTime & _pos ) -{ - // we'll increase the position of every TCO, posated behind _pos, by - // one tact - for( tcoVector::iterator it = m_trackContentObjects.begin(); - it != m_trackContentObjects.end(); ++it ) - { - if( ( *it )->startPosition() >= _pos ) - { - ( *it )->movePosition( (*it)->startPosition() + 64 ); - } - } -} - - - - -void trackContentWidget::removeTact( const midiTime & _pos ) -{ - // we'll decrease the position of every TCO, posated behind _pos, by - // one tact - for( tcoVector::iterator it = m_trackContentObjects.begin(); - it != m_trackContentObjects.end(); ++it ) - { - if( ( *it )->startPosition() >= _pos ) - { - ( *it )->movePosition( tMax( ( *it )->startPosition() - - 64, 0 ) ); - } + m_tcoViews.erase( it ); + engine::getSong()->setModified(); } } @@ -739,8 +677,8 @@ void trackContentWidget::removeTact( const midiTime & _pos ) void trackContentWidget::update( void ) { - for( tcoVector::iterator it = m_trackContentObjects.begin(); - it != m_trackContentObjects.end(); ++it ) + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) { ( *it )->setFixedHeight( height() - 2 ); ( *it )->update(); @@ -751,6 +689,80 @@ void trackContentWidget::update( void ) +// resposible for moving track-content-widgets to appropriate position after +// change of visible viewport +void trackContentWidget::changePosition( const midiTime & _new_pos ) +{ +// const int tcos = numOfTCOs(); + + if( m_trackView->getTrackContainerView() == engine::getBBEditor() ) + { + const int cur_bb = engine::getBBTrackContainer()->currentBB(); + int i = 0; + // first show TCO for current BB... + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it, ++i ) + { + if( i == cur_bb ) + { + ( *it )->move( 0, ( *it )->y() ); + ( *it )->raise(); + ( *it )->show(); + } + else + { + ( *it )->lower(); + } + } + // ...then hide others to avoid flickering + i = 0; + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it, ++i ) + { + if( i != cur_bb ) + { + ( *it )->hide(); + } + } + return; + } + + midiTime pos = _new_pos; + if( pos < 0 ) + { + pos = m_trackView->getTrackContainerView()->currentPosition(); + } + + const Sint32 begin = pos; + const Sint32 end = endPosition( pos ); + const float ppt = m_trackView->getTrackContainerView()->pixelsPerTact(); + + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) + { + trackContentObjectView * tcov = *it; + trackContentObject * tco = tcov->getTrackContentObject(); + tco->changeLength( tco->length() ); + Sint32 ts = tco->startPosition(); + Sint32 te = tco->endPosition(); + if( ( ts >= begin && ts <= end ) || + ( te >= begin && te <= end ) || + ( ts <= begin && te >= end ) ) + { + tcov->move( static_cast( ( ts - begin ) * ppt / + 64 ), tcov->y() ); + tcov->show(); + } + else + { + tcov->hide(); + } + } +} + + + + void trackContentWidget::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, "tco_" + @@ -765,12 +777,13 @@ void trackContentWidget::dropEvent( QDropEvent * _de ) QString type = stringPairDrag::decodeKey( _de ); QString value = stringPairDrag::decodeValue( _de ); if( type == ( "tco_" + QString::number( getTrack()->type() ) ) && - getTrack()->getTrackContainer()->fixedTCOs() == FALSE ) + m_trackView->getTrackContainerView()->fixedTCOs() == FALSE ) { const midiTime pos = getPosition( _de->pos().x() ).toNearestTact(); - trackContentObject * tco = addTCO( getTrack()->createTCO( - pos ) ); + trackContentObject * tco = getTrack()->addTCO( + getTrack()->createTCO( pos ) ); + // value contains our XML-data so simply create a // multimediaProject which does the rest for us... multimediaProject mmp( value, FALSE ); @@ -778,6 +791,8 @@ void trackContentWidget::dropEvent( QDropEvent * _de ) // the user doesn't expect... tco->restoreState( mmp.content().firstChild().toElement() ); tco->movePosition( pos ); + + _de->accept(); } } @@ -789,7 +804,7 @@ void trackContentWidget::dropEvent( QDropEvent * _de ) void trackContentWidget::mousePressEvent( QMouseEvent * _me ) { - if( getTrack()->getTrackContainer()->allowRubberband() == TRUE ) + if( m_trackView->getTrackContainerView()->allowRubberband() == TRUE ) { QWidget::mousePressEvent( _me ); } @@ -798,14 +813,16 @@ void trackContentWidget::mousePressEvent( QMouseEvent * _me ) QWidget::mousePressEvent( _me ); } else if( _me->button() == Qt::LeftButton && - getTrack()->getTrackContainer()->fixedTCOs() == FALSE ) + !m_trackView->getTrackContainerView()->fixedTCOs() ) { const midiTime pos = getPosition( _me->x() ).getTact() * 64; - trackContentObject * tco = addTCO( getTrack()->createTCO( - pos ) ); + trackContentObject * tco = getTrack()->addTCO( + getTrack()->createTCO( pos ) ); + tco->saveJournallingState( FALSE ); tco->movePosition( pos ); tco->restoreJournallingState(); + } } @@ -817,15 +834,15 @@ void trackContentWidget::paintEvent( QPaintEvent * _pe ) QPainter p( this ); p.fillRect( rect(), QColor( 96, 96, 96 ) ); - const trackContainer * tc = getTrack()->getTrackContainer(); - if( !tc->fixedTCOs() ) + const trackContainerView * tcv = m_trackView->getTrackContainerView(); + if( !tcv->fixedTCOs() ) { - const int offset = (int)( ( tc->currentPosition() % 4 ) * - tc->pixelsPerTact() ); + const int offset = (int)( ( tcv->currentPosition() % 4 ) * + tcv->pixelsPerTact() ); // draw vertical lines p.setPen( QColor( 128, 128, 128 ) ); for( int x = -offset; x < width(); - x += (int) tc->pixelsPerTact() ) + x += (int) tcv->pixelsPerTact() ) { p.drawLine( x, 0, x, height() ); } @@ -848,7 +865,7 @@ void trackContentWidget::undoStep( journalEntry & _je ) saveJournallingState( FALSE ); switch( _je.actionID() ) { - case ADD_TCO: + case AddTrackContentObject: { QMap map = _je.data().toMap(); trackContentObject * tco = @@ -856,18 +873,18 @@ void trackContentWidget::undoStep( journalEntry & _je ) engine::getProjectJournal()->getJournallingObject( map["id"].toInt() ) ); multimediaProject mmp( - multimediaProject::JOURNAL_DATA ); + multimediaProject::JournalData ); tco->saveState( mmp, mmp.content() ); map["state"] = mmp.toString(); _je.data() = map; - tco->close(); + tco->deleteLater(); break; } - case REMOVE_TCO: + case RemoveTrackContentObject: { - trackContentObject * tco = addTCO( - getTrack()->createTCO( + trackContentObject * tco = + getTrack()->addTCO( getTrack()->createTCO( midiTime( 0 ) ) ); multimediaProject mmp( _je.data().toMap()["state"].toString(), FALSE ); @@ -886,13 +903,17 @@ void trackContentWidget::redoStep( journalEntry & _je ) { switch( _je.actionID() ) { - case ADD_TCO: - case REMOVE_TCO: - _je.actionID() = ( _je.actionID() == ADD_TCO ) ? - REMOVE_TCO : ADD_TCO; + case AddTrackContentObject: + case RemoveTrackContentObject: + _je.actionID() = ( _je.actionID() == + AddTrackContentObject ) ? + RemoveTrackContentObject : + AddTrackContentObject; undoStep( _je ); - _je.actionID() = ( _je.actionID() == ADD_TCO ) ? - REMOVE_TCO : ADD_TCO; + _je.actionID() = ( _je.actionID() == + AddTrackContentObject ) ? + RemoveTrackContentObject : + AddTrackContentObject; break; } } @@ -902,7 +923,7 @@ void trackContentWidget::redoStep( journalEntry & _je ) track * trackContentWidget::getTrack( void ) { - return( m_trackWidget->getTrack() ); + return( m_trackView->getTrack() ); } @@ -910,13 +931,25 @@ track * trackContentWidget::getTrack( void ) midiTime trackContentWidget::getPosition( int _mouse_x ) { - const trackContainer * tc = getTrack()->getTrackContainer(); - return( midiTime( tc->currentPosition() + _mouse_x * 64 / - static_cast( tc->pixelsPerTact() ) ) ); + return( midiTime( m_trackView->getTrackContainerView()-> + currentPosition() + _mouse_x * 64 / + static_cast( m_trackView-> + getTrackContainerView()->pixelsPerTact() ) ) ); } +midiTime trackContentWidget::endPosition( const midiTime & _pos_start ) +{ + const float ppt = m_trackView->getTrackContainerView()->pixelsPerTact(); + const int w = width(); + return( _pos_start + static_cast( w * 64 / ppt ) ); +} + + + + + // =========================================================================== // trackOperationsWidget @@ -930,9 +963,9 @@ QPixmap * trackOperationsWidget::s_muteOnDisabled; QPixmap * trackOperationsWidget::s_muteOnEnabled; -trackOperationsWidget::trackOperationsWidget( trackWidget * _parent ) : +trackOperationsWidget::trackOperationsWidget( trackView * _parent ) : QWidget( _parent ), - m_trackWidget( _parent ), + m_trackView( _parent ), m_automationDisabled( FALSE ) { if( s_grip == NULL ) @@ -967,7 +1000,7 @@ trackOperationsWidget::trackOperationsWidget( trackWidget * _parent ) : m_muteBtn = new pixmapButton( this, tr( "Mute" ) ); - m_muteBtn->model()->setTrack( m_trackWidget->getTrack() ); + m_muteBtn->model()->setTrack( m_trackView->getTrack() ); m_muteBtn->setActiveGraphic( *s_muteOnEnabled ); m_muteBtn->setInactiveGraphic( *s_muteOffEnabled ); m_muteBtn->setCheckable( TRUE ); @@ -1019,14 +1052,14 @@ void trackOperationsWidget::mousePressEvent( QMouseEvent * _me ) { if( _me->button() == Qt::LeftButton && engine::getMainWindow()->isCtrlPressed() == TRUE && - m_trackWidget->getTrack()->type() != track::BB_TRACK ) + m_trackView->getTrack()->type() != track::BBTrack ) { - multimediaProject mmp( multimediaProject::DRAG_N_DROP_DATA ); - m_trackWidget->getTrack()->saveState( mmp, mmp.content() ); + multimediaProject mmp( multimediaProject::DragNDropData ); + m_trackView->getTrack()->saveState( mmp, mmp.content() ); new stringPairDrag( QString( "track_%1" ).arg( - m_trackWidget->getTrack()->type() ), + m_trackView->getTrack()->type() ), mmp.toString(), QPixmap::grabWidget( - &m_trackWidget->getTrackSettingsWidget() ), + m_trackView->getTrackSettingsWidget() ), this ); } else if( _me->button() == Qt::LeftButton ) @@ -1044,14 +1077,14 @@ void trackOperationsWidget::paintEvent( QPaintEvent * _pe ) { QPainter p( this ); p.fillRect( rect(), QColor( 128, 128, 128 ) ); - if( m_trackWidget->isMovingTrack() == FALSE ) + if( m_trackView->isMovingTrack() == FALSE ) { p.drawPixmap( 2, 2, *s_grip ); if( inBBEditor() ) { bbTrack * bb_track = currentBBTrack(); if( !bb_track || bb_track->automationDisabled( - m_trackWidget->getTrack() ) ) + m_trackView->getTrack() ) ) { if( !m_automationDisabled ) { @@ -1094,7 +1127,7 @@ void trackOperationsWidget::paintEvent( QPaintEvent * _pe ) void trackOperationsWidget::cloneTrack( void ) { engine::getMixer()->lock(); - m_trackWidget->getTrack()->clone(); + m_trackView->getTrack()->clone(); engine::getMixer()->unlock(); } @@ -1103,10 +1136,11 @@ void trackOperationsWidget::cloneTrack( void ) void trackOperationsWidget::removeTrack( void ) { + m_trackView->close(); engine::getMixer()->lock(); - m_trackWidget->getTrack()->getTrackContainer()->removeTrack( - m_trackWidget->getTrack() ); + delete m_trackView->getTrack(); engine::getMixer()->unlock(); + m_trackView->deleteLater(); } @@ -1115,7 +1149,7 @@ void trackOperationsWidget::removeTrack( void ) void trackOperationsWidget::setMuted( bool _muted ) { m_muteBtn->setChecked( _muted ); - m_trackWidget->getTrackContentWidget().update(); + m_trackView->getTrackContentWidget()->update(); } @@ -1125,7 +1159,7 @@ void trackOperationsWidget::muteBtnRightClicked( void ) { const bool m = muted(); // next function might modify our mute-state, // so save it now - m_trackWidget->getTrack()->getTrackContainer()-> + m_trackView->getTrack()->getTrackContainer()-> setMutedOfAllTracks( m ); setMuted( !m ); } @@ -1143,7 +1177,7 @@ void trackOperationsWidget::updateMenu( void ) if( bb_track ) { if( bb_track->automationDisabled( - m_trackWidget->getTrack() ) ) + m_trackView->getTrack() ) ) { to_menu->addAction( embed::getIconPixmap( "led_off", 16, 16 ), @@ -1172,7 +1206,7 @@ void trackOperationsWidget::updateMenu( void ) void trackOperationsWidget::enableAutomation( void ) { - currentBBTrack()->enableAutomation( m_trackWidget->getTrack() ); + currentBBTrack()->enableAutomation( m_trackView->getTrack() ); } @@ -1180,7 +1214,7 @@ void trackOperationsWidget::enableAutomation( void ) void trackOperationsWidget::disableAutomation( void ) { - currentBBTrack()->disableAutomation( m_trackWidget->getTrack() ); + currentBBTrack()->disableAutomation( m_trackView->getTrack() ); } @@ -1188,7 +1222,8 @@ void trackOperationsWidget::disableAutomation( void ) bbTrack * trackOperationsWidget::currentBBTrack( void ) { - return( bbTrack::findBBTrack( engine::getBBEditor()->currentBB() ) ); + return( bbTrack::findBBTrack( + engine::getBBTrackContainer()->currentBB() ) ); } @@ -1196,7 +1231,7 @@ bbTrack * trackOperationsWidget::currentBBTrack( void ) bool trackOperationsWidget::inBBEditor( void ) { - return( m_trackWidget->getTrack()->getTrackContainer() + return( m_trackView->getTrackContainerView() == engine::getBBEditor() ); } @@ -1205,330 +1240,21 @@ bool trackOperationsWidget::inBBEditor( void ) -// =========================================================================== -// trackWidget -// =========================================================================== - -trackWidget::trackWidget( track * _track, QWidget * _parent ) : - QWidget( _parent ), - m_track( _track ), - m_trackOperationsWidget( this ), - m_trackSettingsWidget( this ), - m_trackContentWidget( this ), - m_action( NONE ) -{ - m_trackOperationsWidget.setAutoFillBackground( TRUE ); - QPalette pal; - pal.setColor( m_trackOperationsWidget.backgroundRole(), - QColor( 128, 128, 128 ) ); - m_trackOperationsWidget.setPalette( pal ); - - - m_trackSettingsWidget.setAutoFillBackground( TRUE ); - pal.setColor( m_trackSettingsWidget.backgroundRole(), - QColor( 64, 64, 64 ) ); - m_trackSettingsWidget.setPalette( pal ); - - QHBoxLayout * layout = new QHBoxLayout( this ); - layout->setMargin( 0 ); - layout->setSpacing( 0 ); - layout->addWidget( &m_trackOperationsWidget ); - layout->addWidget( &m_trackSettingsWidget ); - layout->addWidget( &m_trackContentWidget, 1 ); - - resizeEvent( NULL ); - - setAcceptDrops( TRUE ); -} - - - - -trackWidget::~trackWidget() -{ -} - - - - -void trackWidget::resizeEvent( QResizeEvent * _re ) -{ - m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH, height() - 1 ); - m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH, - height() - 1 ); - m_trackContentWidget.setFixedHeight( height() - 1 ); -} - - - - -void trackWidget::update( void ) -{ - m_trackContentWidget.update(); - if( !m_track->getTrackContainer()->fixedTCOs() ) - { - changePosition(); - } - QWidget::update(); -} - - - - -// resposible for moving track-content-widgets to appropriate position after -// change of visible viewport -void trackWidget::changePosition( const midiTime & _new_pos ) -{ - const int tcos = m_trackContentWidget.numOfTCOs(); - - if( m_track->getTrackContainer() == engine::getBBEditor() ) - { - const int showTco = engine::getBBEditor()->currentBB(); - for( int i = 0; i < tcos; ++i ) - { - trackContentObject * tco = m_trackContentWidget.getTCO( - i ); - if( i == showTco ) - { - tco->move( 0, tco->y() ); - tco->show(); - } - else - { - tco->hide(); - } - } - return; - } - - midiTime pos = _new_pos; - if( pos < 0 ) - { - pos = m_track->getTrackContainer()->currentPosition(); - } - - const Sint32 begin = pos; - const Sint32 end = endPosition( pos ); - const float ppt = m_track->getTrackContainer()->pixelsPerTact(); - - for( int i = 0; i < tcos; ++i ) - { - trackContentObject * tco = m_trackContentWidget.getTCO( i ); - tco->changeLength( tco->length() ); - Sint32 ts = tco->startPosition(); - Sint32 te = tco->endPosition(); - if( ( ts >= begin && ts <= end ) || - ( te >= begin && te <= end ) || - ( ts <= begin && te >= end ) ) - { - tco->move( static_cast( ( ts - begin ) * ppt / - 64 ), tco->y() ); - tco->show(); - } - else - { - tco->hide(); - } - } -} - - - - -void trackWidget::undoStep( journalEntry & _je ) -{ - saveJournallingState( FALSE ); - switch( _je.actionID() ) - { - case MOVE_TRACK: - { - trackContainer * tc = m_track->getTrackContainer(); - if( _je.data().toInt() > 0 ) - { - tc->moveTrackUp( m_track ); - } - else - { - tc->moveTrackDown( m_track ); - } - break; - } - case RESIZE_TRACK: - setFixedHeight( tMax( height() + - _je.data().toInt(), - MINIMAL_TRACK_HEIGHT ) ); - m_track->getTrackContainer()->realignTracks(); - break; - } - restoreJournallingState(); -} - - - - -void trackWidget::redoStep( journalEntry & _je ) -{ - journalEntry je( _je.actionID(), -_je.data().toInt() ); - undoStep( je ); -} - - - - -void trackWidget::dragEnterEvent( QDragEnterEvent * _dee ) -{ - stringPairDrag::processDragEnterEvent( _dee, "track_" + - QString::number( m_track->type() ) ); -} - - - - -void trackWidget::dropEvent( QDropEvent * _de ) -{ - QString type = stringPairDrag::decodeKey( _de ); - QString value = stringPairDrag::decodeValue( _de ); - if( type == ( "track_" + QString::number( m_track->type() ) ) ) - { - // value contains our XML-data so simply create a - // multimediaProject which does the rest for us... - multimediaProject mmp( value, FALSE ); - engine::getMixer()->lock(); - m_track->restoreState( mmp.content().firstChild().toElement() ); - engine::getMixer()->unlock(); - _de->accept(); - } -} - - - - -void trackWidget::mousePressEvent( QMouseEvent * _me ) -{ - if( m_track->getTrackContainer()->allowRubberband() == TRUE ) - { - QWidget::mousePressEvent( _me ); - } - else if( _me->button() == Qt::LeftButton ) - { - if( engine::getMainWindow()->isShiftPressed() == TRUE ) - { - m_action = RESIZE_TRACK; - QCursor::setPos( mapToGlobal( QPoint( _me->x(), - height() ) ) ); - QCursor c( Qt::SizeVerCursor); - QApplication::setOverrideCursor( c ); - } - else - { - m_action = MOVE_TRACK; - - QCursor c( Qt::SizeAllCursor ); - QApplication::setOverrideCursor( c ); - // update because in move-mode, all elements in - // track-op-widgets are hidden as a visual feedback - m_trackOperationsWidget.update(); - } - - _me->accept(); - } - else - { - QWidget::mousePressEvent( _me ); - } -} - - - - -void trackWidget::mouseMoveEvent( QMouseEvent * _me ) -{ - if( m_track->getTrackContainer()->allowRubberband() == TRUE ) - { - QWidget::mouseMoveEvent( _me ); - } - else if( m_action == MOVE_TRACK ) - { - trackContainer * tc = m_track->getTrackContainer(); - // look which track-widget the mouse-cursor is over - const trackWidget * track_at_y = tc->trackWidgetAt( - mapTo( tc->contentWidget(), _me->pos() ).y() ); - // a track-widget not equal to ourself? - if( track_at_y != NULL && track_at_y != this ) - { - // then move us up/down there! - if( _me->y() < 0 ) - { - tc->moveTrackUp( m_track ); - } - else - { - tc->moveTrackDown( m_track ); - } - addJournalEntry( journalEntry( MOVE_TRACK, _me->y() ) ); - } - } - else if( m_action == RESIZE_TRACK ) - { - setFixedHeight( tMax( _me->y(), MINIMAL_TRACK_HEIGHT ) ); - m_track->getTrackContainer()->realignTracks(); - } -} - - - - -void trackWidget::mouseReleaseEvent( QMouseEvent * _me ) -{ - m_action = NONE; - while( QApplication::overrideCursor() != NULL ) - { - QApplication::restoreOverrideCursor(); - } - m_trackOperationsWidget.update(); - - QWidget::mouseReleaseEvent( _me ); -} - - - - -void trackWidget::paintEvent( QPaintEvent * _pe ) -{ - QStyleOption opt; - opt.initFrom( this ); - QPainter p( this ); - style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this ); -} - - - - -midiTime trackWidget::endPosition( const midiTime & _pos_start ) -{ - const float ppt = m_track->getTrackContainer()->pixelsPerTact(); - const int cww = m_trackContentWidget.width(); - return( _pos_start + static_cast( cww * 64 / ppt ) ); -} - - - - - - // =========================================================================== // track // =========================================================================== -track::track( trackContainer * _tc, bool _create_widget ) : +track::track( TrackTypes _type, trackContainer * _tc ) : + model( _tc ), m_trackContainer( _tc ), - m_trackWidget( NULL ) + m_type( _type ), + m_name(), + m_pixmap( NULL ), + m_mutedModel( FALSE, this ), + m_trackContentObjects(), + m_automationPatterns() { - if( _create_widget ) - { - m_trackWidget = new trackWidget( this, m_trackContainer ); - m_trackContainer->addTrack( this ); - } + m_trackContainer->addTrack( this ); } @@ -1536,13 +1262,13 @@ track::track( trackContainer * _tc, bool _create_widget ) : track::~track() { - if( m_trackContainer == engine::getBBEditor() - && engine::getSongEditor() ) + if( m_trackContainer == engine::getBBTrackContainer() + && engine::getSong() ) { - QList tracks = engine::getSongEditor()->tracks(); + QList tracks = engine::getSong()->tracks(); for( int i = 0; i < tracks.size(); ++i ) { - if( tracks[i]->type() == BB_TRACK ) + if( tracks[i]->type() == BBTrack ) { bbTrack * bb_track = (bbTrack *)tracks[i]; if( bb_track->automationDisabled( this ) ) @@ -1554,18 +1280,16 @@ track::~track() } } - if( m_trackWidget != NULL ) + while( !m_trackContentObjects.isEmpty() ) { - m_trackContainer->removeTrack( this ); - - m_trackWidget->hide(); - m_trackWidget->deleteLater(); - m_trackWidget = NULL; + delete m_trackContentObjects.last(); } + m_trackContainer->removeTrack( this ); + for( QList::iterator it = - m_automation_patterns.begin(); - it != m_automation_patterns.end(); + m_automationPatterns.begin(); + it != m_automationPatterns.end(); ++it ) { ( *it )->forgetTrack(); @@ -1575,18 +1299,18 @@ track::~track() -track * track::create( trackTypes _tt, trackContainer * _tc ) +track * track::create( TrackTypes _tt, trackContainer * _tc ) { track * t = NULL; switch( _tt ) { - case INSTRUMENT_TRACK: t = new instrumentTrack( _tc ); break; - case BB_TRACK: t = new bbTrack( _tc ); break; - case SAMPLE_TRACK: t = new sampleTrack( _tc ); break; + case InstrumentTrack: t = new instrumentTrack( _tc ); break; + case BBTrack: t = new bbTrack( _tc ); break; +// case SampleTrack: t = new sampleTrack( _tc ); break; // case EVENT_TRACK: // case VIDEO_TRACK: - case AUTOMATION_TRACK: t = new automationTrack( _tc ); break; + case AutomationTrack: t = new automationTrack( _tc ); break; default: break; } @@ -1598,10 +1322,16 @@ track * track::create( trackTypes _tt, trackContainer * _tc ) -void track::create( const QDomElement & _this, trackContainer * _tc ) +track * track::create( const QDomElement & _this, trackContainer * _tc ) { - create( static_cast( _this.attribute( "type" ).toInt() ), - _tc )->restoreState( _this ); + track * t = create( + static_cast( _this.attribute( "type" ).toInt() ), + _tc ); + if( t != NULL ) + { + t->restoreState( _this ); + } + return( t ); } @@ -1618,22 +1348,15 @@ void track::clone( void ) -tact track::length( void ) const -{ - return( getTrackContentWidget()->length() ); -} - - void track::saveSettings( QDomDocument & _doc, QDomElement & _this ) { - int num_of_tcos = getTrackContentWidget()->numOfTCOs(); - _this.setTagName( "track" ); _this.setAttribute( "type", type() ); _this.setAttribute( "muted", muted() ); - _this.setAttribute( "height", m_trackWidget->height() ); +// ### TODO +// _this.setAttribute( "height", m_trackView->height() ); QDomElement ts_de = _doc.createElement( nodeName() ); // let actual track (instrumentTrack, bbTrack, sampleTrack etc.) save @@ -1642,10 +1365,10 @@ void track::saveSettings( QDomDocument & _doc, QDomElement & _this ) saveTrackSpecificSettings( _doc, ts_de ); // now save settings of all TCO's - for( int i = 0; i < num_of_tcos; ++i ) + for( tcoVector::const_iterator it = m_trackContentObjects.begin(); + it != m_trackContentObjects.end(); ++it ) { - trackContentObject * tco = getTCO( i ); - tco->saveState( _doc, _this ); + ( *it )->saveState( _doc, _this ); } } @@ -1662,8 +1385,11 @@ void track::loadSettings( const QDomElement & _this ) setMuted( _this.attribute( "muted" ).toInt() ); - - getTrackContentWidget()->removeAllTCOs(); + while( !m_trackContentObjects.empty() ) + { + delete m_trackContentObjects.front(); + m_trackContentObjects.erase( m_trackContentObjects.begin() ); + } QDomNode node = _this.firstChild(); while( !node.isNull() ) @@ -1680,21 +1406,19 @@ void track::loadSettings( const QDomElement & _this ) trackContentObject * tco = createTCO( midiTime( 0 ) ); tco->restoreState( node.toElement() ); - getTrackContentWidget()->saveJournallingState( - FALSE ); + saveJournallingState( FALSE ); addTCO( tco ); - getTrackContentWidget()-> - restoreJournallingState(); + restoreJournallingState(); } } node = node.nextSibling(); } - +/* if( _this.attribute( "height" ).toInt() >= MINIMAL_TRACK_HEIGHT ) { - m_trackWidget->setFixedHeight( + m_trackView->setFixedHeight( _this.attribute( "height" ).toInt() ); - } + }*/ } @@ -1702,15 +1426,28 @@ void track::loadSettings( const QDomElement & _this ) trackContentObject * track::addTCO( trackContentObject * _tco ) { - return( getTrackContentWidget()->addTCO( _tco ) ); + m_trackContentObjects.push_back( _tco ); + +// emit dataChanged(); + emit trackContentObjectAdded( _tco ); + + //engine::getSongEditor()->setModified(); + return( _tco ); // just for convenience } -void track::removeTCO( int _tco_num ) +void track::removeTCO( trackContentObject * _tco ) { - getTrackContentWidget()->removeTCO( _tco_num ); + tcoVector::iterator it = qFind( m_trackContentObjects.begin(), + m_trackContentObjects.end(), + _tco ); + if( it != m_trackContentObjects.end() ) + { + m_trackContentObjects.erase( it ); + engine::getSong()->setModified(); + } } @@ -1718,7 +1455,7 @@ void track::removeTCO( int _tco_num ) int track::numOfTCOs( void ) { - return( getTrackContentWidget()->numOfTCOs() ); + return( m_trackContentObjects.size() ); } @@ -1726,7 +1463,13 @@ int track::numOfTCOs( void ) trackContentObject * track::getTCO( int _tco_num ) { - return( getTrackContentWidget()->getTCO( _tco_num ) ); + if( _tco_num < m_trackContentObjects.size() ) + { + return( m_trackContentObjects[_tco_num] ); + } + printf( "called track::getTCO( %d ), " + "but TCO %d doesn't exist\n", _tco_num, _tco_num ); + return( addTCO( createTCO( _tco_num * 64 ) ) ); } @@ -1735,12 +1478,17 @@ trackContentObject * track::getTCO( int _tco_num ) int track::getTCONum( trackContentObject * _tco ) { - for( int i = 0; i < getTrackContentWidget()->numOfTCOs(); ++i ) +// for( int i = 0; i < getTrackContentWidget()->numOfTCOs(); ++i ) + tcoVector::iterator it = qFind( m_trackContentObjects.begin(), + m_trackContentObjects.end(), + _tco ); + if( it != m_trackContentObjects.end() ) { - if( getTCO( i ) == _tco ) +/* if( getTCO( i ) == _tco ) { return( i ); - } + }*/ + return( it - m_trackContentObjects.begin() ); } qWarning( "track::getTCONum(...) -> _tco not found!\n" ); return( 0 ); @@ -1753,9 +1501,10 @@ void track::getTCOsInRange( QList & _tco_v, const midiTime & _start, const midiTime & _end ) { - for( int i = 0; i < getTrackContentWidget()->numOfTCOs(); ++i ) + for( tcoVector::iterator it_o = m_trackContentObjects.begin(); + it_o != m_trackContentObjects.end(); ++it_o ) { - trackContentObject * tco = getTCO( i ); + trackContentObject * tco = ( *it_o );//getTCO( i ); Sint32 s = tco->startPosition(); Sint32 e = tco->endPosition(); if( ( s <= _end ) && ( e >= _start ) ) @@ -1789,15 +1538,72 @@ void track::getTCOsInRange( QList & _tco_v, void track::swapPositionOfTCOs( int _tco_num1, int _tco_num2 ) { - getTrackContentWidget()->swapPositionOfTCOs( _tco_num1, _tco_num2 ); + // TODO: range-checking + qSwap( m_trackContentObjects[_tco_num1], + m_trackContentObjects[_tco_num2] ); + + const midiTime pos = m_trackContentObjects[_tco_num1]->startPosition(); + + m_trackContentObjects[_tco_num1]->movePosition( + m_trackContentObjects[_tco_num2]->startPosition() ); + m_trackContentObjects[_tco_num2]->movePosition( pos ); } +void track::insertTact( const midiTime & _pos ) +{ + // we'll increase the position of every TCO, posated behind _pos, by + // one tact + for( tcoVector::iterator it = m_trackContentObjects.begin(); + it != m_trackContentObjects.end(); ++it ) + { + if( ( *it )->startPosition() >= _pos ) + { + ( *it )->movePosition( (*it)->startPosition() + 64 ); + } + } +} + + + + +void track::removeTact( const midiTime & _pos ) +{ + // we'll decrease the position of every TCO, posated behind _pos, by + // one tact + for( tcoVector::iterator it = m_trackContentObjects.begin(); + it != m_trackContentObjects.end(); ++it ) + { + if( ( *it )->startPosition() >= _pos ) + { + ( *it )->movePosition( tMax( ( *it )->startPosition() - + 64, 0 ) ); + } + } +} + + + + +tact track::length( void ) const +{ + // find last end-position + midiTime last = 0; + for( tcoVector::const_iterator it = m_trackContentObjects.begin(); + it != m_trackContentObjects.end(); ++it ) + { + last = tMax( ( *it )->endPosition(), last ); + } + return( last.getTact() + ( ( last.getTact64th() != 0 ) ? 1 : 0 ) ); +} + + + void track::addAutomationPattern( automationPattern * _pattern ) { - m_automation_patterns.append( _pattern ); + m_automationPatterns.append( _pattern ); } @@ -1805,7 +1611,7 @@ void track::addAutomationPattern( automationPattern * _pattern ) void track::removeAutomationPattern( automationPattern * _pattern ) { - m_automation_patterns.removeAll( _pattern ); + m_automationPatterns.removeAll( _pattern ); } @@ -1814,8 +1620,8 @@ void track::removeAutomationPattern( automationPattern * _pattern ) void track::sendMidiTime( const midiTime & _time ) { for( QList::iterator it = - m_automation_patterns.begin(); - it != m_automation_patterns.end(); + m_automationPatterns.begin(); + it != m_automationPatterns.end(); ++it ) { ( *it )->processMidiTime( _time ); @@ -1825,6 +1631,294 @@ void track::sendMidiTime( const midiTime & _time ) + + +// =========================================================================== +// trackView +// =========================================================================== + +trackView::trackView( track * _track, trackContainerView * _tcv ) : + QWidget( _tcv->contentWidget() ), + modelView( NULL/*_track*/ ), + m_track( _track ), + m_trackContainerView( _tcv ), + m_trackOperationsWidget( this ), + m_trackSettingsWidget( this ), + m_trackContentWidget( this ), + m_action( NoAction ) +{ + m_trackOperationsWidget.setAutoFillBackground( TRUE ); + QPalette pal; + pal.setColor( m_trackOperationsWidget.backgroundRole(), + QColor( 128, 128, 128 ) ); + m_trackOperationsWidget.setPalette( pal ); + + + m_trackSettingsWidget.setAutoFillBackground( TRUE ); + pal.setColor( m_trackSettingsWidget.backgroundRole(), + QColor( 64, 64, 64 ) ); + m_trackSettingsWidget.setPalette( pal ); + + QHBoxLayout * layout = new QHBoxLayout( this ); + layout->setMargin( 0 ); + layout->setSpacing( 0 ); + layout->addWidget( &m_trackOperationsWidget ); + layout->addWidget( &m_trackSettingsWidget ); + layout->addWidget( &m_trackContentWidget, 1 ); + + resizeEvent( NULL ); + + setAcceptDrops( TRUE ); + setAttribute( Qt::WA_DeleteOnClose ); + + + connect( m_track, SIGNAL( destroyed( QObject * ) ), + this, SLOT( close() ), Qt::QueuedConnection ); + connect( m_track, + SIGNAL( trackContentObjectAdded( trackContentObject * ) ), + this, SLOT( createTCOView( trackContentObject * ) ), + Qt::QueuedConnection ); + + // create views for already existing TCOs + for( track::tcoVector::iterator it = + m_track->m_trackContentObjects.begin(); + it != m_track->m_trackContentObjects.end(); ++it ) + { + createTCOView( *it ); + } +// setModel( m_track ); + + m_trackContainerView->addTrackView( this ); +} + + + + +trackView::~trackView() +{ +} + + + + +void trackView::resizeEvent( QResizeEvent * _re ) +{ + m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH, height() - 1 ); + m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH, + height() - 1 ); + m_trackContentWidget.setFixedHeight( height() - 1 ); +} + + + + +void trackView::update( void ) +{ + m_trackContentWidget.update(); + if( !m_trackContainerView->fixedTCOs() ) + { + m_trackContentWidget.changePosition(); + } + QWidget::update(); +} + + + + +bool trackView::close( void ) +{ + m_trackContainerView->removeTrackView( this ); + QWidget::close(); +} + + + + +void trackView::modelChanged( void ) +{ + m_track = castModel(); + assert( m_track != NULL ); + connect( m_track, SIGNAL( destroyed( QObject * ) ), + this, SLOT( close() ), Qt::QueuedConnection ); + modelView::modelChanged(); +} + + + + +void trackView::undoStep( journalEntry & _je ) +{ + saveJournallingState( FALSE ); + switch( _je.actionID() ) + { + case MoveTrack: + if( _je.data().toInt() > 0 ) + { + m_trackContainerView->moveTrackViewUp( this ); + } + else + { + m_trackContainerView->moveTrackViewDown( this ); + } + break; + case ResizeTrack: + setFixedHeight( tMax( height() + + _je.data().toInt(), + MINIMAL_TRACK_HEIGHT ) ); + m_trackContainerView->realignTracks(); + break; + } + restoreJournallingState(); +} + + + + +void trackView::redoStep( journalEntry & _je ) +{ + journalEntry je( _je.actionID(), -_je.data().toInt() ); + undoStep( je ); +} + + + + +void trackView::dragEnterEvent( QDragEnterEvent * _dee ) +{ + stringPairDrag::processDragEnterEvent( _dee, "track_" + + QString::number( m_track->type() ) ); +} + + + + +void trackView::dropEvent( QDropEvent * _de ) +{ + QString type = stringPairDrag::decodeKey( _de ); + QString value = stringPairDrag::decodeValue( _de ); + if( type == ( "track_" + QString::number( m_track->type() ) ) ) + { + // value contains our XML-data so simply create a + // multimediaProject which does the rest for us... + multimediaProject mmp( value, FALSE ); + engine::getMixer()->lock(); + m_track->restoreState( mmp.content().firstChild().toElement() ); + engine::getMixer()->unlock(); + _de->accept(); + } +} + + + + +void trackView::mousePressEvent( QMouseEvent * _me ) +{ + if( m_trackContainerView->allowRubberband() == TRUE ) + { + QWidget::mousePressEvent( _me ); + } + else if( _me->button() == Qt::LeftButton ) + { + if( engine::getMainWindow()->isShiftPressed() == TRUE ) + { + m_action = ResizeTrack; + QCursor::setPos( mapToGlobal( QPoint( _me->x(), + height() ) ) ); + QCursor c( Qt::SizeVerCursor); + QApplication::setOverrideCursor( c ); + } + else + { + m_action = MoveTrack; + + QCursor c( Qt::SizeAllCursor ); + QApplication::setOverrideCursor( c ); + // update because in move-mode, all elements in + // track-op-widgets are hidden as a visual feedback + m_trackOperationsWidget.update(); + } + + _me->accept(); + } + else + { + QWidget::mousePressEvent( _me ); + } +} + + + + +void trackView::mouseMoveEvent( QMouseEvent * _me ) +{ + if( m_trackContainerView->allowRubberband() == TRUE ) + { + QWidget::mouseMoveEvent( _me ); + } + else if( m_action == MoveTrack ) + { + // look which track-widget the mouse-cursor is over + const trackView * track_at_y = + m_trackContainerView->trackViewAt( + mapTo( m_trackContainerView->contentWidget(), + _me->pos() ).y() ); + // a track-widget not equal to ourself? + if( track_at_y != NULL && track_at_y != this ) + { + // then move us up/down there! + if( _me->y() < 0 ) + { + m_trackContainerView->moveTrackViewUp( this ); + } + else + { + m_trackContainerView->moveTrackViewDown( this ); + } + addJournalEntry( journalEntry( MoveTrack, _me->y() ) ); + } + } + else if( m_action == ResizeTrack ) + { + setFixedHeight( tMax( _me->y(), MINIMAL_TRACK_HEIGHT ) ); + m_trackContainerView->realignTracks(); + } +} + + + + +void trackView::mouseReleaseEvent( QMouseEvent * _me ) +{ + m_action = NoAction; + while( QApplication::overrideCursor() != NULL ) + { + QApplication::restoreOverrideCursor(); + } + m_trackOperationsWidget.update(); + + QWidget::mouseReleaseEvent( _me ); +} + + + + +void trackView::paintEvent( QPaintEvent * _pe ) +{ + QStyleOption opt; + opt.initFrom( this ); + QPainter p( this ); + style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this ); +} + + + + +void trackView::createTCOView( trackContentObject * _tco ) +{ + _tco->createView( this ); +} + + #include "track.moc" diff --git a/src/core/track_container.cpp b/src/core/track_container.cpp index e55177f8f1..6eb7a140e0 100644 --- a/src/core/track_container.cpp +++ b/src/core/track_container.cpp @@ -4,7 +4,7 @@ * track_container.cpp - implementation of base-class for all track-containers * like Song-Editor, BB-Editor... * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -50,35 +50,16 @@ #include "mmp.h" #include "project_journal.h" #include "rubberband.h" -#include "song_editor.h" +#include "song.h" #include "string_pair_drag.h" #include "track.h" trackContainer::trackContainer( void ) : - m_currentPosition( 0, 0 ), - m_scrollArea( new scrollArea( this ) ), - m_ppt( DEFAULT_PIXELS_PER_TACT ), - m_rubberBand( new rubberBand( m_scrollArea ) ), - m_origin() + model( NULL ), + journallingObject(), + m_tracks() { - QVBoxLayout * layout = new QVBoxLayout( this ); - layout->setMargin( 0 ); - layout->setSpacing( 0 ); - layout->addWidget( m_scrollArea ); - - QWidget * scrollContent = new QWidget; - m_scrollLayout = new QVBoxLayout( scrollContent ); - m_scrollLayout->setMargin( 0 ); - m_scrollLayout->setSpacing( 0 ); - m_scrollLayout->setSizeConstraint( QLayout::SetMinimumSize ); - - m_scrollArea->setWidget( scrollContent ); - - m_scrollArea->show(); - m_rubberBand->hide(); - - setAcceptDrops( TRUE ); } @@ -99,7 +80,8 @@ void trackContainer::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setTagName( classNodeName() ); _this.setAttribute( "type", nodeName() ); - mainWindow::saveWidgetState( this, _this ); +// ### TODO + //mainWindow::saveWidgetState( this, _this ); // save settings of each track for( int i = 0; i < m_tracks.size(); ++i ) @@ -150,9 +132,9 @@ void trackContainer::loadSettings( const QDomElement & _this ) node = node.nextSibling(); } - mainWindow::restoreWidgetState( this, _this ); +// ### TODO +// mainWindow::restoreWidgetState( this, _this ); - realignTracks(); pd->setValue( start_val + _this.childNodes().count() ); @@ -168,16 +150,11 @@ void trackContainer::loadSettings( const QDomElement & _this ) void trackContainer::addTrack( track * _track ) { - QMap map; - map["id"] = _track->id(); - addJournalEntry( journalEntry( ADD_TRACK, map ) ); - - m_tracks.push_back( _track ); - m_scrollLayout->addWidget( _track->getTrackWidget() ); - connect( this, SIGNAL( positionChanged( const midiTime & ) ), - _track->getTrackWidget(), - SLOT( changePosition( const midiTime & ) ) ); - realignTracks(); + if( _track->type() != track::AutomationTrack ) + { + m_tracks.push_back( _track ); + emit trackAdded( _track ); + } } @@ -188,24 +165,11 @@ void trackContainer::removeTrack( track * _track ) int index = m_tracks.indexOf( _track ); if( index != -1 ) { - QMap map; - multimediaProject mmp( multimediaProject::JOURNAL_DATA ); - _track->saveState( mmp, mmp.content() ); - map["id"] = _track->id(); - map["state"] = mmp.toString(); - addJournalEntry( journalEntry( REMOVE_TRACK, map ) ); - m_tracks.removeAt( index ); - disconnect( _track->getTrackWidget() ); - m_scrollLayout->removeWidget( _track->getTrackWidget() ); - - delete _track; - - realignTracks(); - if( engine::getSongEditor() ) + if( engine::getSong() ) { - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } } @@ -213,45 +177,6 @@ void trackContainer::removeTrack( track * _track ) -void trackContainer::moveTrackUp( track * _track ) -{ - for( int i = 1; i < m_tracks.size(); ++i ) - { - if( m_tracks[i] == _track ) - { - bbTrack::swapBBTracks( m_tracks[i], m_tracks[i - 1] ); - QWidget * tw = m_tracks[i]->getTrackWidget(); - m_scrollLayout->removeWidget( tw ); - m_scrollLayout->insertWidget( i - 1, tw ); - m_tracks.swap( i - 1, i ); - realignTracks(); - break; - } - } -} - - - - -void trackContainer::moveTrackDown( track * _track ) -{ - for( int i = 0; i < m_tracks.size() - 1; ++i ) - { - if( m_tracks[i] == _track ) - { - bbTrack::swapBBTracks( m_tracks[i], m_tracks[i + 1] ); - QWidget * tw = m_tracks[i]->getTrackWidget(); - m_scrollLayout->removeWidget( tw ); - m_scrollLayout->insertWidget( i + 1, tw ); - m_tracks.swap( i, i + 1 ); - realignTracks(); - break; - } - } -} - - - void trackContainer::updateAfterTrackAdd( void ) { @@ -260,69 +185,24 @@ void trackContainer::updateAfterTrackAdd( void ) -void trackContainer::realignTracks( void ) -{ - QWidget * content = m_scrollArea->widget(); - content->setFixedWidth( width() - - m_scrollArea->verticalScrollBar()->width() ); - content->setFixedHeight( content->minimumSizeHint().height() ); - - for( int i = 0; i < m_tracks.size(); ++i ) - { - trackWidget * tw = m_tracks[i]->getTrackWidget(); - tw->show(); - tw->update(); - } -} - - - void trackContainer::clearAllTracks( void ) { while( !m_tracks.empty() ) { - removeTrack( m_tracks.last() ); + delete m_tracks.takeLast(); } } -const trackWidget * trackContainer::trackWidgetAt( const int _y ) const +int trackContainer::countTracks( track::TrackTypes _tt ) const { - const int abs_y = _y + m_scrollArea->viewport()->y(); - int y_cnt = 0; + int cnt = 0; for( int i = 0; i < m_tracks.size(); ++i ) { - const int y_cnt1 = y_cnt; - y_cnt += m_tracks[i]->getTrackWidget()->height(); - if( abs_y >= y_cnt1 && abs_y < y_cnt ) - { - return( m_tracks[i]->getTrackWidget() ); - } - } - return( NULL ); -} - - - - -bool trackContainer::allowRubberband( void ) const -{ - return( FALSE ); -} - - - - -Uint16 trackContainer::countTracks( track::trackTypes _tt ) const -{ - Uint16 cnt = 0; - for( int i = 0; i < m_tracks.size(); ++i ) - { - if( m_tracks[i]->type() == _tt || - _tt == track::TOTAL_TRACK_TYPES ) + if( m_tracks[i]->type() == _tt || _tt == track::NumTrackTypes ) { ++cnt; } @@ -344,23 +224,208 @@ void trackContainer::setMutedOfAllTracks( bool _muted ) -const QList trackContainer::tracks( void ) const + + + + + + + +trackContainerView::trackContainerView( trackContainer * _tc ) : + QWidget(), + modelView( NULL ), + m_currentPosition( 0, 0 ), + m_tc( _tc ), + m_trackViews(), + m_scrollArea( new scrollArea( this ) ), + m_ppt( DEFAULT_PIXELS_PER_TACT ), + m_rubberBand( new rubberBand( m_scrollArea ) ), + m_origin() { - return( m_tracks ); + QVBoxLayout * layout = new QVBoxLayout( this ); + layout->setMargin( 0 ); + layout->setSpacing( 0 ); + layout->addWidget( m_scrollArea ); + + QWidget * scrollContent = new QWidget; + m_scrollLayout = new QVBoxLayout( scrollContent ); + m_scrollLayout->setMargin( 0 ); + m_scrollLayout->setSpacing( 0 ); + m_scrollLayout->setSizeConstraint( QLayout::SetMinimumSize ); + + m_scrollArea->setWidget( scrollContent ); + + m_scrollArea->show(); + m_rubberBand->hide(); + + setAcceptDrops( TRUE ); + + connect( m_tc, SIGNAL( trackAdded( track * ) ), + this, SLOT( createTrackView( track * ) ), + Qt::QueuedConnection ); } -QList trackContainer::tracks( void ) +trackContainerView::~trackContainerView() { - return( m_tracks ); + while( !m_trackViews.empty() ) + { + delete m_trackViews.takeLast(); + } } -void trackContainer::setPixelsPerTact( Uint16 _ppt ) + +trackView * trackContainerView::addTrackView( trackView * _tv ) +{ + QMap map; + map["id"] = _tv->getTrack()->id(); + addJournalEntry( journalEntry( AddTrack, map ) ); + + m_trackViews.push_back( _tv ); + m_scrollLayout->addWidget( _tv ); + connect( this, SIGNAL( positionChanged( const midiTime & ) ), + _tv->getTrackContentWidget(), + SLOT( changePosition( const midiTime & ) ) ); + realignTracks(); + return( _tv ); +} + + + + +void trackContainerView::removeTrackView( trackView * _tv ) +{ + int index = m_trackViews.indexOf( _tv ); + if( index != -1 ) + { + QMap map; + multimediaProject mmp( multimediaProject::JournalData ); + _tv->getTrack()->saveState( mmp, mmp.content() ); + map["id"] = _tv->getTrack()->id(); + map["state"] = mmp.toString(); + addJournalEntry( journalEntry( RemoveTrack, map ) ); + + m_trackViews.removeAt( index ); + + disconnect( _tv ); + m_scrollLayout->removeWidget( _tv ); + + realignTracks(); + if( engine::getSong() ) + { + engine::getSong()->setModified(); + } + } +} + + + + +void trackContainerView::moveTrackViewUp( trackView * _tv ) +{ + for( int i = 1; i < m_trackViews.size(); ++i ) + { + trackView * t = m_trackViews[i]; + if( t == _tv ) + { + bbTrack::swapBBTracks( t->getTrack(), + m_trackViews[i - 1]->getTrack() ); + m_scrollLayout->removeWidget( t ); + m_scrollLayout->insertWidget( i - 1, t ); + m_tc->m_tracks.swap( i - 1, i ); + m_trackViews.swap( i - 1, i ); + realignTracks(); + break; + } + } +} + + + + +void trackContainerView::moveTrackViewDown( trackView * _tv ) +{ + for( int i = 0; i < m_trackViews.size()-1; ++i ) + { + trackView * t = m_trackViews[i]; + if( t == _tv ) + { + bbTrack::swapBBTracks( t->getTrack(), + m_trackViews[i + 1]->getTrack() ); + m_scrollLayout->removeWidget( t ); + m_scrollLayout->insertWidget( i + 1, t ); + m_tc->m_tracks.swap( i, i + 1 ); + m_trackViews.swap( i, i + 1 ); + realignTracks(); + break; + } + } +} + + + + + +void trackContainerView::realignTracks( void ) +{ + QWidget * content = m_scrollArea->widget(); + content->setFixedWidth( width() + - m_scrollArea->verticalScrollBar()->width() ); + content->setFixedHeight( content->minimumSizeHint().height() ); + + for( trackViewList::iterator it = m_trackViews.begin(); + it != m_trackViews.end(); ++it ) + { + ( *it )->show(); + ( *it )->update(); + } +} + + + + +void trackContainerView::createTrackView( track * _t ) +{ + _t->createView( this ); +} + + + + +const trackView * trackContainerView::trackViewAt( const int _y ) const +{ + const int abs_y = _y + m_scrollArea->viewport()->y(); + int y_cnt = 0; + for( trackViewList::const_iterator it = m_trackViews.begin(); + it != m_trackViews.end(); ++it ) + { + const int y_cnt1 = y_cnt; + y_cnt += ( *it )->height(); + if( abs_y >= y_cnt1 && abs_y < y_cnt ) + { + return( *it ); + } + } + return( NULL ); +} + + + + +bool trackContainerView::allowRubberband( void ) const +{ + return( FALSE ); +} + + + + +void trackContainerView::setPixelsPerTact( int _ppt ) { m_ppt = _ppt; } @@ -368,34 +433,47 @@ void trackContainer::setPixelsPerTact( Uint16 _ppt ) -void trackContainer::undoStep( journalEntry & _je ) +void trackContainerView::clearAllTracks( void ) +{ + while( !m_trackViews.empty() ) + { + trackView * tv = m_trackViews.takeLast(); + track * t = tv->getTrack(); + delete tv; + delete t; + } +} + + + + +void trackContainerView::undoStep( journalEntry & _je ) { saveJournallingState( FALSE ); switch( _je.actionID() ) { - case ADD_TRACK: + case AddTrack: { QMap map = _je.data().toMap(); - track * tr = + track * t = dynamic_cast( engine::getProjectJournal()->getJournallingObject( map["id"].toInt() ) ); - assert( tr != NULL ); - multimediaProject mmp( - multimediaProject::JOURNAL_DATA ); - tr->saveState( mmp, mmp.content() ); + assert( t != NULL ); + multimediaProject mmp( multimediaProject::JournalData ); + t->saveState( mmp, mmp.content() ); map["state"] = mmp.toString(); _je.data() = map; - removeTrack( tr ); + t->deleteLater(); break; } - case REMOVE_TRACK: + case RemoveTrack: { multimediaProject mmp( _je.data().toMap()["state"].toString(), FALSE ); track::create( mmp.content().firstChild().toElement(), - this ); + m_tc ); break; } } @@ -405,17 +483,17 @@ void trackContainer::undoStep( journalEntry & _je ) -void trackContainer::redoStep( journalEntry & _je ) +void trackContainerView::redoStep( journalEntry & _je ) { switch( _je.actionID() ) { - case ADD_TRACK: - case REMOVE_TRACK: - _je.actionID() = ( _je.actionID() == ADD_TRACK ) ? - REMOVE_TRACK : ADD_TRACK; + case AddTrack: + case RemoveTrack: + _je.actionID() = ( _je.actionID() == AddTrack ) ? + RemoveTrack : AddTrack; undoStep( _je ); - _je.actionID() = ( _je.actionID() == ADD_TRACK ) ? - REMOVE_TRACK : ADD_TRACK; + _je.actionID() = ( _je.actionID() == AddTrack ) ? + RemoveTrack : AddTrack; break; } } @@ -423,19 +501,19 @@ void trackContainer::redoStep( journalEntry & _je ) -void trackContainer::dragEnterEvent( QDragEnterEvent * _dee ) +void trackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, QString( "presetfile,sampledata,samplefile,instrument,midifile," "track_%1,track_%2" ). - arg( track::INSTRUMENT_TRACK ). - arg( track::SAMPLE_TRACK ) ); + arg( track::InstrumentTrack ). + arg( track::SampleTrack ) ); } -void trackContainer::dropEvent( QDropEvent * _de ) +void trackContainerView::dropEvent( QDropEvent * _de ) { QString type = stringPairDrag::decodeKey( _de ); QString value = stringPairDrag::decodeValue( _de ); @@ -443,45 +521,45 @@ void trackContainer::dropEvent( QDropEvent * _de ) if( type == "instrument" ) { instrumentTrack * it = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, - this ) ); + track::create( track::InstrumentTrack, + m_tc ) ); it->loadInstrument( value ); - it->toggledInstrumentTrackButton( TRUE ); + //it->toggledInstrumentTrackButton( TRUE ); _de->accept(); } else if( type == "sampledata" || type == "samplefile" ) { instrumentTrack * it = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, - this ) ); + track::create( track::InstrumentTrack, + m_tc ) ); QString iname = type == "sampledata" ? "audiofileprocessor" : engine::sampleExtensions()[fileItem::extension( value )]; instrument * i = it->loadInstrument( iname ); i->setParameter( type, value ); - it->toggledInstrumentTrackButton( TRUE ); + //it->toggledInstrumentTrackButton( TRUE ); _de->accept(); } else if( type == "presetfile" ) { multimediaProject mmp( value ); instrumentTrack * it = dynamic_cast( - track::create( track::INSTRUMENT_TRACK, - this ) ); + track::create( track::InstrumentTrack, + m_tc ) ); it->loadTrackSpecificSettings( mmp.content().firstChild(). toElement() ); - it->toggledInstrumentTrackButton( TRUE ); + //it->toggledInstrumentTrackButton( TRUE ); _de->accept(); } else if( type == "midifile" ) { - importFilter::import( value, this ); + importFilter::import( value, m_tc ); _de->accept(); } else if( type.left( 6 ) == "track_" ) { multimediaProject mmp( value, FALSE ); - track::create( mmp.content().firstChild().toElement(), this ); + track::create( mmp.content().firstChild().toElement(), m_tc ); _de->accept(); } engine::getMixer()->unlock(); @@ -490,7 +568,7 @@ void trackContainer::dropEvent( QDropEvent * _de ) -void trackContainer::mousePressEvent( QMouseEvent * _me ) +void trackContainerView::mousePressEvent( QMouseEvent * _me ) { if( allowRubberband() == TRUE ) { @@ -498,12 +576,13 @@ void trackContainer::mousePressEvent( QMouseEvent * _me ) m_rubberBand->setGeometry( QRect( m_origin, QSize() ) ); m_rubberBand->show(); } + QWidget::mousePressEvent( _me ); } -void trackContainer::mouseMoveEvent( QMouseEvent * _me ) +void trackContainerView::mouseMoveEvent( QMouseEvent * _me ) { if( rubberBandActive() == TRUE ) { @@ -511,31 +590,34 @@ void trackContainer::mouseMoveEvent( QMouseEvent * _me ) m_scrollArea->mapFromParent( _me->pos() ) ). normalized() ); } + QWidget::mouseMoveEvent( _me ); } -void trackContainer::mouseReleaseEvent( QMouseEvent * _me ) +void trackContainerView::mouseReleaseEvent( QMouseEvent * _me ) { m_rubberBand->hide(); + QWidget::mouseReleaseEvent( _me ); } -void trackContainer::resizeEvent( QResizeEvent * ) +void trackContainerView::resizeEvent( QResizeEvent * _re ) { realignTracks(); + QWidget::resizeEvent( _re ); } -trackContainer::scrollArea::scrollArea( trackContainer * _parent ) : +trackContainerView::scrollArea::scrollArea( trackContainerView * _parent ) : QScrollArea( _parent ), - m_trackContainer( _parent ) + m_trackContainerView( _parent ) { setFrameStyle( QFrame::NoFrame ); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); @@ -545,20 +627,20 @@ trackContainer::scrollArea::scrollArea( trackContainer * _parent ) : -trackContainer::scrollArea::~scrollArea() +trackContainerView::scrollArea::~scrollArea() { } -void trackContainer::scrollArea::wheelEvent( QWheelEvent * _we ) +void trackContainerView::scrollArea::wheelEvent( QWheelEvent * _we ) { // always pass wheel-event to parent-widget (song-editor // bb-editor etc.) because they might want to use it for zooming // or scrolling left/right if a modifier-key is pressed, otherwise // they do not accept it and we pass it up to QScrollArea - m_trackContainer->wheelEvent( _we ); + m_trackContainerView->wheelEvent( _we ); if( !_we->isAccepted() ) { QScrollArea::wheelEvent( _we ); @@ -568,6 +650,7 @@ void trackContainer::scrollArea::wheelEvent( QWheelEvent * _we ) + #include "track_container.moc" diff --git a/src/lib/journalling_object.cpp b/src/lib/journalling_object.cpp index d72fcb2d2f..5a23bd47c9 100644 --- a/src/lib/journalling_object.cpp +++ b/src/lib/journalling_object.cpp @@ -3,7 +3,7 @@ /* * journalling_object.cpp - implementation of journalling-object related stuff * - * Copyright (c) 2006-2007 Tobias Doerffel + * Copyright (c) 2006-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -38,7 +38,9 @@ journallingObject::journallingObject( void ) : m_id( engine::getProjectJournal()->allocID( this ) ), m_journalEntries(), m_currentJournalEntry( m_journalEntries.end() ), - m_journalling( TRUE ) + m_journalling( TRUE ), + m_journallingStateStack(), + m_hook( NULL ) { } @@ -47,6 +49,10 @@ journallingObject::journallingObject( void ) : journallingObject::~journallingObject() { + if( m_hook ) + { + m_hook->m_hookedIn = NULL; + } if( engine::getProjectJournal() ) { engine::getProjectJournal()->freeID( id() ); @@ -125,6 +131,15 @@ void journallingObject::restoreState( const QDomElement & _this ) +void journallingObject::setHook( journallingObjectHook * _hook ) +{ + m_hook = _hook; + m_hook->m_hookedIn = this; +} + + + + void journallingObject::addJournalEntry( const journalEntry & _je ) { if( engine::getProjectJournal()->isJournalling() && isJournalling() ) diff --git a/src/lib/mmp.cpp b/src/lib/mmp.cpp index 48fbead8c4..44ef7f3dff 100644 --- a/src/lib/mmp.cpp +++ b/src/lib/mmp.cpp @@ -40,26 +40,26 @@ multimediaProject::typeDescStruct - multimediaProject::s_types[multimediaProject::PROJ_TYPE_COUNT] = + multimediaProject::s_types[multimediaProject::NumProjectTypes] = { - { multimediaProject::UNKNOWN, "unknown" }, - { multimediaProject::SONG_PROJECT, "song" }, - { multimediaProject::SONG_PROJECT_TEMPLATE, "songtemplate" }, + { multimediaProject::UnknownType, "unknown" }, + { multimediaProject::SongProject, "song" }, + { multimediaProject::SongProjectTemplate, "songtemplate" }, #warning compat-code, use upgrade feature - { multimediaProject::INSTRUMENT_TRACK_SETTINGS, + { multimediaProject::InstrumentTrackSettings, "instrumenttracksettings,channelsettings" }, - { multimediaProject::DRAG_N_DROP_DATA, "dnddata" }, - { multimediaProject::CLIPBOARD_DATA, "clipboard-data" }, - { multimediaProject::JOURNAL_DATA, "journaldata" }, - { multimediaProject::EFFECT_SETTINGS, "effectsettings" }, - { multimediaProject::VIDEO_PROJECT, "videoproject" }, - { multimediaProject::BURN_PROJECT, "burnproject" }, - { multimediaProject::PLAYLIST, "playlist" } + { multimediaProject::DragNDropData, "dnddata" }, + { multimediaProject::ClipboardData, "clipboard-data" }, + { multimediaProject::JournalData, "journaldata" }, + { multimediaProject::EffectSettings, "effectsettings" }, + { multimediaProject::VideoProject, "videoproject" }, + { multimediaProject::BurnProject, "burnproject" }, + { multimediaProject::Playlist, "playlist" } } ; -multimediaProject::multimediaProject( projectTypes _project_type ) : +multimediaProject::multimediaProject( ProjectTypes _project_type ) : QDomDocument( "multimedia-project" ), m_content(), m_head(), @@ -193,7 +193,7 @@ QString multimediaProject::nameWithExtension( const QString & _fn ) const { switch( type() ) { - case SONG_PROJECT: + case SongProject: if( _fn.section( '.', -1 ) != "mmp" && _fn.section( '.', -1 ) != "mpt" && _fn.section( '.', -1 ) != "mmpz" ) @@ -206,13 +206,13 @@ QString multimediaProject::nameWithExtension( const QString & _fn ) const return( _fn + ".mmp" ); } break; - case SONG_PROJECT_TEMPLATE: + case SongProjectTemplate: if( _fn.section( '.',-1 ) != "mpt" ) { return( _fn + ".mpt" ); } break; - case INSTRUMENT_TRACK_SETTINGS: + case InstrumentTrackSettings: if( _fn.section( '.', -2, -1 ) != "cs.xml" ) { return( _fn + ".cs.xml" ); @@ -228,8 +228,8 @@ QString multimediaProject::nameWithExtension( const QString & _fn ) const bool multimediaProject::writeFile( QString & _fn, bool _overwrite_check ) { - if( type() == SONG_PROJECT || type() == SONG_PROJECT_TEMPLATE - || type() == INSTRUMENT_TRACK_SETTINGS ) + if( type() == SongProject || type() == SongProjectTemplate + || type() == InstrumentTrackSettings ) { cleanMetaNodes( documentElement() ); } @@ -284,7 +284,7 @@ bool multimediaProject::writeFile( QString & _fn, bool _overwrite_check ) -multimediaProject::projectTypes multimediaProject::typeOfFile( +multimediaProject::ProjectTypes multimediaProject::typeOfFile( const QString & _fn ) { multimediaProject m( _fn, TRUE, FALSE ); @@ -294,10 +294,10 @@ multimediaProject::projectTypes multimediaProject::typeOfFile( -multimediaProject::projectTypes multimediaProject::type( +multimediaProject::ProjectTypes multimediaProject::type( const QString & _type_name ) { - for( int i = 0; i < PROJ_TYPE_COUNT; ++i ) + for( int i = 0; i < NumProjectTypes; ++i ) { if( s_types[i].m_name == _type_name || ( s_types[i].m_name.contains( "," ) && ( @@ -306,26 +306,26 @@ multimediaProject::projectTypes multimediaProject::type( ) { - return( static_cast( + return( static_cast( i ) ); } } - return( UNKNOWN ); + return( UnknownType ); } -QString multimediaProject::typeName( projectTypes _project_type ) +QString multimediaProject::typeName( ProjectTypes _project_type ) { - if( _project_type >= UNKNOWN && _project_type < PROJ_TYPE_COUNT ) + if( _project_type >= UnknownType && _project_type < NumProjectTypes ) { return( s_types[_project_type].m_name #warning compat-code, use upgrade feature .section( ',', 0, 0 ) ); } - return( s_types[UNKNOWN].m_name ); + return( s_types[UnknownType].m_name ); } @@ -606,6 +606,20 @@ void multimediaProject::upgrade( void ) } } + if( version < "0.4.0-svn20080129" ) + { + QDomNodeList list; + while( !( list = + elementsByTagName( "arpandchords" ) ).isEmpty() ) + { + QDomElement aac = list.item( 0 ).toElement(); + aac.setTagName( "arpeggiator" ); + QDomNode cloned = aac.cloneNode(); + cloned.toElement().setTagName( "chordcreator" ); + aac.parentNode().appendChild( cloned ); + } + } + if( !m_head.hasAttribute( "mastervol" ) ) { m_head.setAttribute( "mastervol", 100 ); diff --git a/src/lib/project_journal.cpp b/src/lib/project_journal.cpp index b78ae7f098..6986fffbea 100644 --- a/src/lib/project_journal.cpp +++ b/src/lib/project_journal.cpp @@ -30,7 +30,7 @@ #include "project_journal.h" #include "engine.h" #include "journalling_object.h" -#include "song_editor.h" +#include "song.h" #include "automatable_model_templates.h" @@ -65,7 +65,7 @@ void projectJournal::undo( void ) ( jo = m_joIDs[*--m_currentJournalEntry] ) != NULL ) { jo->undo(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } @@ -86,7 +86,7 @@ void projectJournal::redo( void ) ( jo = m_joIDs[*m_currentJournalEntry++] ) != NULL ) { jo->redo(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } } @@ -98,7 +98,7 @@ void projectJournal::journalEntryAdded( const jo_id_t _id ) m_journalEntries.erase( m_currentJournalEntry, m_journalEntries.end() ); m_journalEntries.push_back( _id ); m_currentJournalEntry = m_journalEntries.end(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } diff --git a/src/midi/midi_alsa_seq.cpp b/src/midi/midi_alsa_seq.cpp index 827d8fda9b..c7fd98cc6d 100644 --- a/src/midi/midi_alsa_seq.cpp +++ b/src/midi/midi_alsa_seq.cpp @@ -33,7 +33,7 @@ #include "config_mgr.h" #include "engine.h" #include "gui_templates.h" -#include "song_editor.h" +#include "song.h" #include "midi_port.h" #include "note.h" #include "automatable_model_templates.h" @@ -63,14 +63,14 @@ midiALSASeq::midiALSASeq( void ) : snd_seq_queue_tempo_t * tempo; snd_seq_queue_tempo_malloc( &tempo ); snd_seq_queue_tempo_set_tempo( tempo, 6000000 / - engine::getSongEditor()->getTempo() ); + engine::getSong()->getTempo() ); snd_seq_queue_tempo_set_ppq( tempo, 16 ); snd_seq_set_queue_tempo( m_seqHandle, m_queueID, tempo ); snd_seq_queue_tempo_free( tempo ); snd_seq_start_queue( m_seqHandle, m_queueID, NULL ); - changeQueueTempo( engine::getSongEditor()->getTempo() ); - connect( engine::getSongEditor(), SIGNAL( tempoChanged( bpm_t ) ), + changeQueueTempo( engine::getSong()->getTempo() ); + connect( engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), this, SLOT( changeQueueTempo( bpm_t ) ) ); // initial list-update diff --git a/src/tracks/automation_track.cpp b/src/tracks/automation_track.cpp index 66099f1bb4..aa3728dd6f 100644 --- a/src/tracks/automation_track.cpp +++ b/src/tracks/automation_track.cpp @@ -4,7 +4,7 @@ * automation_track.cpp - automationTrack handles automation of objects without * a track * - * Copyright (c) 2006 Javier Serrano Polo + * Copyright (c) 2006-2008 Javier Serrano Polo * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -27,12 +27,13 @@ #include "automation_track.h" +#include "automatable_model_templates.h" automationTrack::automationTrack( trackContainer * _tc ) : - track( _tc, FALSE ) + track( AutomationTrack, _tc ) { } @@ -46,18 +47,8 @@ automationTrack::~automationTrack() -track::trackTypes automationTrack::type( void ) const -{ - return( AUTOMATION_TRACK ); -} - - - - -bool automationTrack::play( const midiTime & _start, - const fpp_t _frames, - const f_cnt_t _frame_base, - Sint16 _tco_num ) +bool automationTrack::play( const midiTime & _start, const fpp_t _frames, + const f_cnt_t _frame_base, Sint16 _tco_num ) { sendMidiTime( _start ); return( FALSE ); @@ -88,8 +79,4 @@ void automationTrack::loadTrackSpecificSettings( const QDomElement & _this ) - -#include "automation_track.moc" - - #endif diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp index 5cb3490692..1496048b0a 100644 --- a/src/tracks/bb_track.cpp +++ b/src/tracks/bb_track.cpp @@ -3,7 +3,7 @@ /* * bb_track.cpp - implementation of class bbTrack and bbTCO * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -39,6 +39,7 @@ #include "mixer.h" #include "name_label.h" #include "rename_dialog.h" +#include "song.h" #include "song_editor.h" #include "templates.h" @@ -47,14 +48,15 @@ bbTrack::infoMap bbTrack::s_infoMap; -bbTCO::bbTCO( track * _track, const QColor & _c ) : +bbTCO::bbTCO( track * _track, unsigned int _color ) : trackContentObject( _track ), - m_name( ( dynamic_cast( _track ) != NULL ) ? + m_name(/* ( dynamic_cast( _track ) != NULL ) ? dynamic_cast( _track )->trackLabel()->text() : - QString( "" ) ), - m_color( _c.isValid() ? _c : QColor( 64, 128, 255 ) ) + QString( "" )*/ + "" ), + m_color( _color > 0 ? _color : qRgb( 64, 128, 255 ) ) { - tact t = engine::getBBEditor()->lengthOfBB( + tact t = engine::getBBTrackContainer()->lengthOfBB( bbTrack::numOfBBTrack( getTrack() ) ); if( t > 0 ) { @@ -74,86 +76,6 @@ bbTCO::~bbTCO() -void bbTCO::constructContextMenu( QMenu * _cm ) -{ - QAction * a = new QAction( embed::getIconPixmap( "bb_track" ), - tr( "Open in Beat+Baseline-Editor" ), - _cm ); - _cm->insertAction( _cm->actions()[0], a ); - connect( a, SIGNAL( triggered( bool ) ), this, - SLOT( openInBBEditor( bool ) ) ); - _cm->insertSeparator( _cm->actions()[1] ); - _cm->addSeparator(); - _cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ), - this, SLOT( resetName() ) ); - _cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ), - this, SLOT( changeName() ) ); - _cm->addAction( embed::getIconPixmap( "colorize" ), - tr( "Change color" ), this, SLOT( changeColor() ) ); -} - - - - -void bbTCO::mouseDoubleClickEvent( QMouseEvent * ) -{ - openInBBEditor(); -} - - - - -void bbTCO::paintEvent( QPaintEvent * ) -{ - QColor col = m_color; - if( getTrack()->muted() || muted() ) - { - col = QColor( 160, 160, 160 ); - } - if( isSelected() == TRUE ) - { - col = QColor( tMax( col.red() - 128, 0 ), - tMax( col.green() - 128, 0 ), 255 ); - } - QPainter p( this ); - - QLinearGradient lingrad( 0, 0, 0, height() ); - lingrad.setColorAt( 0, col.light( 130 ) ); - lingrad.setColorAt( 1, col.light( 70 ) ); - p.fillRect( rect(), lingrad ); - - tact t = engine::getBBEditor()->lengthOfBB( bbTrack::numOfBBTrack( - getTrack() ) ); - if( length() > 64 && t > 0 ) - { - for( int x = static_cast( t * pixelsPerTact() ); - x < width()-2; - x += static_cast( t * pixelsPerTact() ) ) - { - p.setPen( col.light( 80 ) ); - p.drawLine( x, 1, x, 5 ); - p.setPen( col.light( 120 ) ); - p.drawLine( x, height() - 6, x, height() - 2 ); - } - } - - p.setPen( col.dark() ); - p.drawRect( 0, 0, rect().right(), rect().bottom() ); - - p.setFont( pointSize<7>( p.font() ) ); - p.setPen( QColor( 0, 0, 0 ) ); - p.drawText( 2, p.fontMetrics().height() - 1, m_name ); - - if( muted() ) - { - p.drawPixmap( 3, p.fontMetrics().height() + 1, - embed::getIconPixmap( "muted", 16, 16 ) ); - } -} - - - - void bbTCO::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "name", m_name ); @@ -167,7 +89,7 @@ void bbTCO::saveSettings( QDomDocument & _doc, QDomElement & _this ) } _this.setAttribute( "len", length() ); _this.setAttribute( "muted", muted() ); - _this.setAttribute( "color", m_color.rgb() ); + _this.setAttribute( "color", m_color ); } @@ -188,17 +110,127 @@ void bbTCO::loadSettings( const QDomElement & _this ) if( _this.attribute( "color" ).toUInt() != 0 ) { - m_color.setRgb( _this.attribute( "color" ).toUInt() ); + m_color = _this.attribute( "color" ).toUInt(); } } -void bbTCO::openInBBEditor( bool ) +trackContentObjectView * bbTCO::createView( trackView * _tv ) { - engine::getBBEditor()->setCurrentBB( bbTrack::numOfBBTrack( - getTrack() ) ); + return( new bbTCOView( this, _tv ) ); +} + + + + + + + + + + +bbTCOView::bbTCOView( trackContentObject * _tco, trackView * _tv ) : + trackContentObjectView( _tco, _tv ), + m_bbTCO( dynamic_cast( _tco ) ) +{ +} + + + + +bbTCOView::~bbTCOView() +{ +} + + + + +void bbTCOView::constructContextMenu( QMenu * _cm ) +{ + QAction * a = new QAction( embed::getIconPixmap( "bb_track" ), + tr( "Open in Beat+Baseline-Editor" ), + _cm ); + _cm->insertAction( _cm->actions()[0], a ); + connect( a, SIGNAL( triggered( bool ) ), + this, SLOT( openInBBEditor() ) ); + _cm->insertSeparator( _cm->actions()[1] ); + _cm->addSeparator(); + _cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ), + this, SLOT( resetName() ) ); + _cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ), + this, SLOT( changeName() ) ); + _cm->addAction( embed::getIconPixmap( "colorize" ), + tr( "Change color" ), this, SLOT( changeColor() ) ); +} + + + + +void bbTCOView::mouseDoubleClickEvent( QMouseEvent * ) +{ + openInBBEditor(); +} + + + + +void bbTCOView::paintEvent( QPaintEvent * ) +{ + QColor col( m_bbTCO->m_color ); + if( m_bbTCO->getTrack()->muted() || m_bbTCO->muted() ) + { + col = QColor( 160, 160, 160 ); + } + if( isSelected() == TRUE ) + { + col = QColor( tMax( col.red() - 128, 0 ), + tMax( col.green() - 128, 0 ), 255 ); + } + QPainter p( this ); + + QLinearGradient lingrad( 0, 0, 0, height() ); + lingrad.setColorAt( 0, col.light( 130 ) ); + lingrad.setColorAt( 1, col.light( 70 ) ); + p.fillRect( rect(), lingrad ); + + tact t = engine::getBBTrackContainer()->lengthOfBB( + bbTrack::numOfBBTrack( m_bbTCO->getTrack() ) ); + if( m_bbTCO->length() > 64 && t > 0 ) + { + for( int x = static_cast( t * pixelsPerTact() ); + x < width()-2; + x += static_cast( t * pixelsPerTact() ) ) + { + p.setPen( col.light( 80 ) ); + p.drawLine( x, 1, x, 5 ); + p.setPen( col.light( 120 ) ); + p.drawLine( x, height() - 6, x, height() - 2 ); + } + } + + p.setPen( col.dark() ); + p.drawRect( 0, 0, rect().right(), rect().bottom() ); + + p.setFont( pointSize<7>( p.font() ) ); + p.setPen( QColor( 0, 0, 0 ) ); + p.drawText( 2, p.fontMetrics().height() - 1, m_bbTCO->m_name ); + + if( m_bbTCO->muted() ) + { + p.drawPixmap( 3, p.fontMetrics().height() + 1, + embed::getIconPixmap( "muted", 16, 16 ) ); + } +} + + + + +void bbTCOView::openInBBEditor( void ) +{ + engine::getBBTrackContainer()->setCurrentBB( bbTrack::numOfBBTrack( + m_bbTCO->getTrack() ) ); engine::getBBEditor()->show(); engine::getBBEditor()->setFocus(); } @@ -206,19 +238,12 @@ void bbTCO::openInBBEditor( bool ) -void bbTCO::openInBBEditor( void ) +void bbTCOView::resetName( void ) { - openInBBEditor( FALSE ); -} - - - - -void bbTCO::resetName( void ) -{ - if( dynamic_cast( getTrack() ) != NULL ) + if( dynamic_cast( getTrackView() ) != NULL ) { - m_name = dynamic_cast( getTrack() )-> + m_bbTCO->m_name = + dynamic_cast( getTrackView() )-> trackLabel()->text(); } } @@ -226,18 +251,18 @@ void bbTCO::resetName( void ) -void bbTCO::changeName( void ) +void bbTCOView::changeName( void ) { - renameDialog rename_dlg( m_name ); + renameDialog rename_dlg( m_bbTCO->m_name ); rename_dlg.exec(); } -void bbTCO::changeColor( void ) +void bbTCOView::changeColor( void ) { - QColor _new_color = QColorDialog::getColor( m_color ); + QColor _new_color = QColorDialog::getColor( m_bbTCO->m_color ); if( !_new_color.isValid() ) { return; @@ -250,10 +275,10 @@ void bbTCO::changeColor( void ) selected.begin(); it != selected.end(); ++it ) { - bbTCO * bb_tco = dynamic_cast( *it ); - if( bb_tco ) + bbTCOView * bb_tcov = dynamic_cast( *it ); + if( bb_tcov ) { - bb_tco->setColor( _new_color ); + bb_tcov->setColor( _new_color ); } } } @@ -266,12 +291,12 @@ void bbTCO::changeColor( void ) -void bbTCO::setColor( QColor _new_color ) +void bbTCOView::setColor( QColor _new_color ) { - if( _new_color != m_color ) + if( _new_color.rgb() != m_bbTCO->m_color ) { - m_color = _new_color; - engine::getSongEditor()->setModified(); + m_bbTCO->m_color = _new_color.rgb(); + engine::getSong()->setModified(); update(); } } @@ -280,33 +305,17 @@ void bbTCO::setColor( QColor _new_color ) -bbTrack::bbTrack( trackContainer * _tc ) : - track( _tc ) -{ - getTrackWidget()->setFixedHeight( 32 ); - // drag'n'drop with bb-tracks only causes troubles (and makes no sense - // too), so disable it - getTrackWidget()->setAcceptDrops( FALSE ); + +bbTrack::bbTrack( trackContainer * _tc ) : + track( BBTrack, _tc ) +{ int bbNum = s_infoMap.size(); s_infoMap[this] = bbNum; - m_trackLabel = new nameLabel( tr( "Beat/Baseline %1" ).arg( bbNum ), - getTrackSettingsWidget() ); - m_trackLabel->setPixmap( embed::getIconPixmap( "bb_track" ) ); - m_trackLabel->setGeometry( 1, 1, DEFAULT_SETTINGS_WIDGET_WIDTH - 2, - 29 ); - m_trackLabel->show(); - connect( m_trackLabel, SIGNAL( clicked() ), - this, SLOT( clickedTrackLabel() ) ); - connect( m_trackLabel, SIGNAL( nameChanged() ), - engine::getBBEditor(), SLOT( updateComboBox() ) ); - connect( m_trackLabel, SIGNAL( pixmapChanged() ), - engine::getBBEditor(), SLOT( updateComboBox() ) ); - - - engine::getBBEditor()->setCurrentBB( bbNum ); - engine::getBBEditor()->updateComboBox(); + setName( tr( "Beat/Baseline %1" ).arg( bbNum ) ); + engine::getBBTrackContainer()->setCurrentBB( bbNum ); + engine::getBBTrackContainer()->updateComboBox(); } @@ -316,8 +325,8 @@ bbTrack::~bbTrack() { engine::getMixer()->removePlayHandles( this ); - int bb = s_infoMap[this]; - engine::getBBEditor()->removeBB( bb ); + const int bb = s_infoMap[this]; + engine::getBBTrackContainer()->removeBB( bb ); for( infoMap::iterator it = s_infoMap.begin(); it != s_infoMap.end(); ++it ) { @@ -327,30 +336,25 @@ bbTrack::~bbTrack() } } s_infoMap.remove( this ); - engine::getBBEditor()->updateComboBox(); + + // remove us from TC so bbTrackContainer::numOfBBs() returns a smaller + // value and thus combobox-updating in bbTrackContainer works well + getTrackContainer()->removeTrack( this ); + engine::getBBTrackContainer()->updateComboBox(); } -track::trackTypes bbTrack::type( void ) const -{ - return( BB_TRACK ); -} - - - // play _frames frames of given TCO within starting with _start -bool FASTCALL bbTrack::play( const midiTime & _start, - const fpp_t _frames, - const f_cnt_t _offset, - Sint16 _tco_num ) +bool bbTrack::play( const midiTime & _start, const fpp_t _frames, + const f_cnt_t _offset, Sint16 _tco_num ) { sendMidiTime( _start ); if( _tco_num >= 0 ) { - return( engine::getBBEditor()->play( _start, _frames, + return( engine::getBBTrackContainer()->play( _start, _frames, _offset, s_infoMap[this] ) ); } @@ -378,7 +382,8 @@ bool FASTCALL bbTrack::play( const midiTime & _start, } if( _start - lastPosition < lastLen ) { - return( engine::getBBEditor()->play( _start - lastPosition, + return( engine::getBBTrackContainer()->play( _start - + lastPosition, _frames, _offset, s_infoMap[this] ) ); @@ -389,6 +394,14 @@ bool FASTCALL bbTrack::play( const midiTime & _start, +trackView * bbTrack::createView( trackContainerView * _tcv ) +{ + return( new bbTrackView( this, _tcv ) ); +} + + + + trackContentObject * bbTrack::createTCO( const midiTime & _pos ) { // if we're creating a new bbTCO, we colorize it according to the @@ -413,20 +426,20 @@ trackContentObject * bbTrack::createTCO( const midiTime & _pos ) void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _this ) { - _this.setAttribute( "name", m_trackLabel->text() ); - _this.setAttribute( "icon", m_trackLabel->pixmapFile() ); + _this.setAttribute( "name", name() ); +// _this.setAttribute( "icon", m_trackLabel->pixmapFile() ); /* _this.setAttribute( "current", s_infoMap[this] == engine::getBBEditor()->currentBB() );*/ if( s_infoMap[this] == 0 && _this.parentNode().parentNode().nodeName() != "clone" && _this.parentNode().nodeName() != "journaldata" ) { - ( (journallingObject *)( engine::getBBEditor() ) )->saveState( - _doc, _this ); + ( (journallingObject *)( engine::getBBTrackContainer() ) )-> + saveState( _doc, _this ); } int track_num = 0; - QList tracks = engine::getBBEditor()->tracks(); + QList tracks = engine::getBBTrackContainer()->tracks(); for( int i = 0; i < tracks.size(); ++i, ++track_num ) { if( automationDisabled( tracks[i] ) ) @@ -444,18 +457,18 @@ void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc, void bbTrack::loadTrackSpecificSettings( const QDomElement & _this ) { - m_trackLabel->setText( _this.attribute( "name" ) ); - if( _this.attribute( "icon" ) != "" ) + setName( _this.attribute( "name" ) ); +/* if( _this.attribute( "icon" ) != "" ) { m_trackLabel->setPixmapFile( _this.attribute( "icon" ) ); - } - engine::getBBEditor()->updateComboBox(); + }*/ +// engine::getBBTrackContainer()->updateComboBox(); QDomNode node = _this.namedItem( trackContainer::classNodeName() ); if( node.isElement() ) { - ( (journallingObject *)engine::getBBEditor() )->restoreState( - node.toElement() ); + ( (journallingObject *)engine::getBBTrackContainer() )-> + restoreState( node.toElement() ); } /* doesn't work yet because bbTrack-ctor also sets current bb so if bb-tracks are created after this function is called, this doesn't @@ -465,7 +478,7 @@ void bbTrack::loadTrackSpecificSettings( const QDomElement & _this ) engine::getBBEditor()->setCurrentBB( s_infoMap[this] ); }*/ - QList tracks = engine::getBBEditor()->tracks(); + QList tracks = engine::getBBTrackContainer()->tracks(); node = _this.firstChild(); while( !node.isNull() ) { @@ -518,17 +531,70 @@ void bbTrack::swapBBTracks( track * _track1, track * _track2 ) if( t1 != NULL && t2 != NULL ) { qSwap( s_infoMap[t1], s_infoMap[t2] ); - engine::getBBEditor()->swapBB( s_infoMap[t1], s_infoMap[t2] ); - engine::getBBEditor()->setCurrentBB( s_infoMap[t1] ); + engine::getBBTrackContainer()->swapBB( s_infoMap[t1], + s_infoMap[t2] ); + engine::getBBTrackContainer()->setCurrentBB( s_infoMap[t1] ); } } -void bbTrack::clickedTrackLabel( void ) + + + + + +bbTrackView::bbTrackView( bbTrack * _bbt, trackContainerView * _tcv ) : + trackView( _bbt, _tcv ), + m_bbTrack( _bbt ) { - engine::getBBEditor()->setCurrentBB( s_infoMap[this] ); + setFixedHeight( 32 ); + // drag'n'drop with bb-tracks only causes troubles (and makes no sense + // too), so disable it + setAcceptDrops( FALSE ); + + m_trackLabel = new nameLabel( _bbt->name(), + getTrackSettingsWidget() ); + m_trackLabel->setPixmap( embed::getIconPixmap( "bb_track" ) ); + m_trackLabel->setGeometry( 1, 1, DEFAULT_SETTINGS_WIDGET_WIDTH - 2, + 29 ); + m_trackLabel->show(); + connect( m_trackLabel, SIGNAL( clicked() ), + this, SLOT( clickedTrackLabel() ) ); + connect( m_trackLabel, SIGNAL( nameChanged( const QString & ) ), + _bbt, SLOT( setName( const QString & ) ) ); + connect( m_trackLabel, SIGNAL( nameChanged( const QString & ) ), + engine::getBBTrackContainer(), SLOT( updateComboBox() ) ); + connect( m_trackLabel, SIGNAL( pixmapChanged() ), + engine::getBBTrackContainer(), SLOT( updateComboBox() ) ); + + setModel( _bbt ); +} + + + + +bbTrackView::~bbTrackView() +{ +} + + + + +bool bbTrackView::close( void ) +{ + engine::getBBEditor()->removeBBView( bbTrack::s_infoMap[m_bbTrack] ); + trackView::close(); +} + + + + +void bbTrackView::clickedTrackLabel( void ) +{ + engine::getBBTrackContainer()->setCurrentBB( + bbTrack::numOfBBTrack( m_bbTrack ) ); engine::getBBEditor()->show(); } diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index 0e064fbf90..5f9f99ce42 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -40,9 +40,9 @@ #include #include #include +#include -#include "arp_and_chords_tab_widget.h" #include "audio_port.h" #include "automatable_model_templates.h" #include "automation_pattern.h" @@ -54,9 +54,12 @@ #include "embed.h" #include "engine.h" #include "instrument_sound_shaping.h" +#include "instrument_sound_shaping_view.h" #include "fade_button.h" #include "gui_templates.h" #include "instrument.h" +#include "instrument_function_views.h" +#include "instrument_midi_io_view.h" #include "led_checkbox.h" #include "main_window.h" #include "midi_client.h" @@ -68,7 +71,7 @@ #include "piano_widget.h" #include "plugin_view.h" #include "sample_play_handle.h" -#include "song_editor.h" +#include "song.h" #include "string_pair_drag.h" #include "tab_widget.h" #include "tooltip.h" @@ -95,10 +98,10 @@ const int INSTRUMENT_HEIGHT = INSTRUMENT_WIDTH; const int PIANO_HEIGHT = 84; +// #### IT: instrumentTrack::instrumentTrack( trackContainer * _tc ) : - track( _tc ), + track( InstrumentTrack, _tc ), midiEventProcessor(), - m_trackType( INSTRUMENT_TRACK ), m_midiPort( engine::getMixer()->getMIDIClient()->addPort( this, tr( "unnamed_channel" ) ) ), m_audioPort( tr( "unnamed_channel" ), this ), @@ -112,9 +115,11 @@ instrumentTrack::instrumentTrack( trackContainer * _tc ) : /* this */ ), // m_effects( /* this */ NULL ), m_instrument( NULL ), - m_instrumentView( NULL ), - m_midiInputAction( NULL ), - m_midiOutputAction( NULL ) + m_soundShaping( this ), + m_arpeggiator( this ), + m_chordCreator( this ), + m_midiIO( this, m_midiPort ), + m_piano( this ) { m_baseNoteModel.setTrack( this ); m_baseNoteModel.setInitValue( DEFAULT_OCTAVE * NOTES_PER_OCTAVE + A ); @@ -131,194 +136,8 @@ instrumentTrack::instrumentTrack( trackContainer * _tc ) : } - setAcceptDrops( TRUE ); - - getTrackWidget()->setFixedHeight( 32 ); - - - // creation of widgets for track-settings-widget - m_tswVolumeKnob = new volumeKnob( knobSmall_17, getTrackSettingsWidget(), - tr( "Channel volume" ) ); - m_tswVolumeKnob->setModel( &m_volumeModel ); - m_tswVolumeKnob->setHintText( tr( "Channel volume:" ) + " ", "%" ); - m_tswVolumeKnob->move( 4, 4 ); - m_tswVolumeKnob->setLabel( tr( "VOL" ) ); - m_tswVolumeKnob->show(); - m_tswVolumeKnob->setWhatsThis( tr( volume_help ) ); - - QPushButton * tsw_midi = new QPushButton( - embed::getIconPixmap( "piano" ), QString::null, - getTrackSettingsWidget() ); - tsw_midi->setGeometry( 32, 2, 28, 28 ); - tsw_midi->show(); - toolTip::add( tsw_midi, tr( "MIDI input/output" ) ); - m_tswMidiMenu = new QMenu( tsw_midi ); - tsw_midi->setMenu( m_tswMidiMenu ); - - - m_tswActivityIndicator = new fadeButton( QColor( 96, 96, 96 ), - QColor( 255, 204, 0 ), - getTrackSettingsWidget() ); - m_tswActivityIndicator->setGeometry( 212, 2, 8, 28 ); - m_tswActivityIndicator->show(); - connect( m_tswActivityIndicator, SIGNAL( pressed( void ) ), - this, SLOT( activityIndicatorPressed() ) ); - connect( m_tswActivityIndicator, SIGNAL( released( void ) ), - this, SLOT( activityIndicatorReleased() ) ); - - - m_tswInstrumentTrackButton = new instrumentTrackButton( this ); - m_tswInstrumentTrackButton->setCheckable( TRUE ); - m_tswInstrumentTrackButton->setGeometry( 64, 2, 144, 28 ); - m_tswInstrumentTrackButton->show(); - connect( m_tswInstrumentTrackButton, SIGNAL( toggled( bool ) ), this, - SLOT( toggledInstrumentTrackButton( bool ) ) ); - - - - // init own layout + widgets - setFocusPolicy( Qt::StrongFocus ); - QVBoxLayout * vlayout = new QVBoxLayout( this ); - vlayout->setMargin( 0 ); - vlayout->setSpacing( 0 ); - - m_generalSettingsWidget = new tabWidget( tr( "GENERAL SETTINGS" ), - this ); - m_generalSettingsWidget->setFixedHeight( 90 ); - - // setup line-edit for changing channel-name - m_instrumentNameLE = new QLineEdit( m_generalSettingsWidget ); - m_instrumentNameLE->setFont( pointSize<8>( - m_instrumentNameLE->font() ) ); - m_instrumentNameLE->setGeometry( 10, 16, 230, 18 ); - connect( m_instrumentNameLE, SIGNAL( textChanged( const QString & ) ), - this, SLOT( textChanged( const QString & ) ) ); - - - // setup volume-knob - m_volumeKnob = new volumeKnob( knobBright_26, m_generalSettingsWidget, - tr( "Channel volume" ) ); - m_volumeKnob->setModel( &m_volumeModel ); - m_volumeKnob->move( 10, 44 ); - m_volumeKnob->setHintText( tr( "Channel volume:" ) + " ", "%" ); - m_volumeKnob->setLabel( tr( "VOLUME" ) ); - - m_volumeKnob->setWhatsThis( tr( volume_help ) ); - //volumeKnob::linkObjects( m_tswVolumeKnob, m_volumeKnob ); - - - // setup surround-area - m_surroundArea = new surroundArea( m_generalSettingsWidget, - tr( "Surround area" ) ); - m_surroundArea->setModel( &m_surroundAreaModel ); - m_surroundArea->move( 20 + m_volumeKnob->width(), 38 ); - m_surroundArea->show(); - m_surroundArea->setWhatsThis( tr( surroundarea_help ) ); - - - // setup spinbox for selecting FX-channel - m_effectChannelNumber = new lcdSpinBox( 2, m_generalSettingsWidget, - tr( "FX channel" ) ); - m_effectChannelNumber->setLabel( tr( "FX CHNL" ) ); - m_effectChannelNumber->move( m_surroundArea->x() + - m_surroundArea->width() + 16, 40 ); - - - m_saveSettingsBtn = new QPushButton( embed::getIconPixmap( - "project_save" ), "", - m_generalSettingsWidget ); - m_saveSettingsBtn->setGeometry( m_effectChannelNumber->x() + - m_effectChannelNumber->width() + 20, 40, - 32, 32 ); - connect( m_saveSettingsBtn, SIGNAL( clicked() ), this, - SLOT( saveSettingsBtnClicked() ) ); - toolTip::add( m_saveSettingsBtn, - tr( "Save current channel settings in a preset-file" ) ); - m_saveSettingsBtn->setWhatsThis( - tr( "Click here, if you want to save current channel settings " - "in a preset-file. Later you can load this preset by " - "double-clicking it in the preset-browser." ) ); - - setName( tr( "Default" ) ); - - m_tabWidget = new tabWidget( "", this ); - m_tabWidget->setFixedHeight( INSTRUMENT_HEIGHT + 12 ); - - - // create other tab-widgets - m_envWidget = new envelopeTabWidget( this ); - m_arpWidget = new arpAndChordsTabWidget( this ); - m_midiWidget = new midiTabWidget( this, m_midiPort ); - m_effectRack = new effectRackView( m_audioPort.getEffects(), - m_tabWidget ); - m_tabWidget->addTab( m_envWidget, tr( "ENV/LFO/FILTER" ), 1 ); - m_tabWidget->addTab( m_arpWidget, tr( "ARP/CHORD" ), 2 ); - m_tabWidget->addTab( m_effectRack, tr( "FX" ), 3 ); - m_tabWidget->addTab( m_midiWidget, tr( "MIDI" ), 4 ); - - // setup piano-widget - m_pianoWidget = new pianoWidget( this ); - m_pianoWidget->setFixedSize( INSTRUMENT_WIDTH, PIANO_HEIGHT ); - - - vlayout->addWidget( m_generalSettingsWidget ); - vlayout->addWidget( m_tabWidget ); - vlayout->addWidget( m_pianoWidget ); - - if( m_midiWidget->m_readablePorts ) - { - m_midiInputAction = m_tswMidiMenu->addMenu( - m_midiWidget->m_readablePorts ); - } - else - { - m_midiInputAction = m_tswMidiMenu->addAction( "" ); - connect( m_midiInputAction, SIGNAL( changed() ), this, - SLOT( midiInSelected() ) ); - } - if( m_midiWidget->m_writeablePorts ) - { - m_midiOutputAction = m_tswMidiMenu->addMenu( - m_midiWidget->m_writeablePorts ); - } - else - { - m_midiOutputAction = m_tswMidiMenu->addAction( "" ); - connect( m_midiOutputAction, SIGNAL( changed() ), this, - SLOT( midiOutSelected() ) ); - } - m_midiInputAction->setText( tr( "MIDI input" ) ); - m_midiOutputAction->setText( tr( "MIDI output" ) ); - if( m_midiWidget->m_readablePorts == NULL || - m_midiWidget->m_writeablePorts == NULL ) - { - connect( m_midiWidget->m_sendCheckBox, - SIGNAL( toggled( bool ) ), - this, SLOT( midiConfigChanged( bool ) ) ); - connect( m_midiWidget->m_receiveCheckBox, - SIGNAL( toggled( bool ) ), - this, SLOT( midiConfigChanged( bool ) ) ); - } - - - // set window-icon - setWindowIcon( embed::getIconPixmap( "instrument_track" ) ); - - - setFixedWidth( INSTRUMENT_WIDTH ); - resize( sizeHint() ); - - if( engine::getMainWindow()->workspace() ) - { - engine::getMainWindow()->workspace()->addSubWindow( this ); - parentWidget()->hide(); - } - else - { - hide(); - } } @@ -327,98 +146,7 @@ instrumentTrack::instrumentTrack( trackContainer * _tc ) : instrumentTrack::~instrumentTrack() { engine::getMixer()->removePlayHandles( this ); - delete m_effectRack; engine::getMixer()->getMIDIClient()->removePort( m_midiPort ); - - if( engine::getMainWindow()->workspace() ) - { - parentWidget()->hide(); - parentWidget()->deleteLater(); - } -} - - - - -void instrumentTrack::saveSettingsBtnClicked( void ) -{ - QFileDialog sfd( this, tr( "Save channel-settings in file" ), "", - tr( "Channel-Settings-File (*.cs.xml)" ) ); - - QString preset_root = configManager::inst()->userPresetsDir(); - if( !QDir( preset_root ).exists() ) - { - QDir().mkdir( preset_root ); - } - if( !QDir( preset_root + instrumentName() ).exists() ) - { - QDir( preset_root ).mkdir( instrumentName() ); - } - - sfd.setDirectory( preset_root + instrumentName() ); - sfd.setFileMode( QFileDialog::AnyFile ); - if( sfd.exec () == QDialog::Accepted && - !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" - ) - { - multimediaProject mmp( - multimediaProject::INSTRUMENT_TRACK_SETTINGS ); - QDomElement _this = mmp.createElement( nodeName() ); - saveTrackSpecificSettings( mmp, _this ); - mmp.content().appendChild( _this ); - QString f = sfd.selectedFiles()[0]; - mmp.writeFile( f ); - } -} - - - - -void instrumentTrack::activityIndicatorPressed( void ) -{ - processInEvent( midiEvent( NOTE_ON, 0, - DEFAULT_OCTAVE * NOTES_PER_OCTAVE + A, - 127 ), midiTime() ); -} - - - - -void instrumentTrack::activityIndicatorReleased( void ) -{ - processInEvent( midiEvent( NOTE_OFF, 0, - DEFAULT_OCTAVE * NOTES_PER_OCTAVE + A, - 0 ), midiTime() ); -} - - - - -void instrumentTrack::midiInSelected( void ) -{ - m_midiInputAction->setChecked( !m_midiInputAction->isChecked() ); - m_midiWidget->m_receiveCheckBox->setChecked( - m_midiInputAction->isChecked() ); -} - - - -void instrumentTrack::midiOutSelected( void ) -{ - m_midiOutputAction->setChecked( !m_midiOutputAction->isChecked() ); - m_midiWidget->m_sendCheckBox->setChecked( - m_midiOutputAction->isChecked() ); -} - - - - -void instrumentTrack::midiConfigChanged( bool ) -{ - m_midiInputAction->setChecked( - m_midiWidget->m_receiveCheckBox->model()->value() ); - m_midiOutputAction->setChecked( - m_midiWidget->m_sendCheckBox->model()->value() ); } @@ -434,7 +162,7 @@ f_cnt_t instrumentTrack::beatLen( notePlayHandle * _n ) const return( len ); } } - return( m_envWidget->envFrames() ); + return( m_soundShaping.envFrames() ); } @@ -460,14 +188,15 @@ void instrumentTrack::processAudioBuffer( sampleFrame * _buf, // is no problem for us since we just bypass the envelopes+LFOs if( _n != NULL ) { - m_envWidget->processAudioBuffer( _buf, _frames, _n ); + m_soundShaping.processAudioBuffer( _buf, _frames, _n ); v_scale *= ( (float) _n->getVolume() / DEFAULT_VOLUME ); } - volumeVector v = m_surroundArea->model()->getVolumeVector( v_scale ); + volumeVector v = m_surroundAreaModel.getVolumeVector( v_scale ); engine::getMixer()->bufferToPort( _buf, - ( _n != NULL ) ? tMin( _n->framesLeftForCurrentPeriod(), _frames ) : - _frames, + ( _n != NULL ) ? tMin( + _n->framesLeftForCurrentPeriod(), _frames ) : + _frames, ( _n != NULL ) ? _n->offset() : 0, v, &m_audioPort ); } @@ -487,7 +216,7 @@ void instrumentTrack::processInEvent( const midiEvent & _me, if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { - m_pianoWidget->setKeyState( + m_piano.setKeyState( _me.key(), TRUE ); } // create temporary note @@ -586,7 +315,7 @@ void instrumentTrack::processOutEvent( const midiEvent & _me, if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { - m_pianoWidget->setKeyState( _me.key(), TRUE ); + m_piano.setKeyState( _me.key(), TRUE ); } if( !configManager::inst()->value( "ui", "disablechannelactivityindicators" ).toInt() ) @@ -595,7 +324,7 @@ void instrumentTrack::processOutEvent( const midiEvent & _me, { return; } - m_tswActivityIndicator->activate(); + emit newNote(); } break; @@ -603,7 +332,7 @@ void instrumentTrack::processOutEvent( const midiEvent & _me, if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { - m_pianoWidget->setKeyState( _me.key(), FALSE ); + m_piano.setKeyState( _me.key(), FALSE ); } break; @@ -621,7 +350,8 @@ void instrumentTrack::playNote( notePlayHandle * _n, bool _try_parallelizing ) { // arpeggio- and chord-widget has to do its work -> adding sub-notes // for chords/arpeggios - m_arpWidget->processNote( _n ); + m_chordCreator.processNote( _n ); + m_arpeggiator.processNote( _n ); if( _n->arpBaseNote() == FALSE && m_instrument != NULL ) { @@ -729,30 +459,22 @@ void instrumentTrack::deleteNotePluginData( notePlayHandle * _n ) void instrumentTrack::setName( const QString & _new_name ) { - // when changing name of channel, also change name of those patterns, - // which have the same name as the channel + // when changing name of track, also change name of those patterns, + // which have the same name as the instrument-track for( int i = 0; i < numOfTCOs(); ++i ) { pattern * p = dynamic_cast( getTCO( i ) ); - if( ( p != NULL && p->name() == m_name ) || p->name() == "" ) + if( ( p != NULL && p->name() == name() ) || p->name() == "" ) { p->setName( _new_name ); } } - m_name = _new_name; - setWindowTitle( m_name ); + track::setName( _new_name ); + m_midiPort->setName( name() ); + m_audioPort.setName( name() ); - if( m_instrumentNameLE->text() != _new_name ) - { - m_instrumentNameLE->setText( m_name ); - } -#ifdef LMMS_DEBUG - assert( m_tswInstrumentTrackButton != NULL ); -#endif - m_tswInstrumentTrackButton->setText( m_name ); - m_midiPort->setName( m_name ); - m_audioPort.setName( m_name ); + emit nameChanged(); } @@ -781,8 +503,7 @@ void instrumentTrack::updateBaseNote( /* bool _modified*/ void ) int instrumentTrack::masterKey( notePlayHandle * _n ) const { - int key = m_baseNoteModel.value() + - engine::getSongEditor()->masterPitch(); + int key = m_baseNoteModel.value() + engine::getSong()->masterPitch(); return( tLimit( _n->key() - ( key - A - DEFAULT_OCTAVE * NOTES_PER_OCTAVE ), 0, NOTES ) ); } @@ -846,8 +567,7 @@ bool FASTCALL instrumentTrack::play( const midiTime & _start, { cur_start -= p->startPosition(); } - if( p->frozen() && - engine::getSongEditor()->exporting() == FALSE ) + if( p->frozen() && engine::getSong()->exporting() == FALSE ) { if( cur_start > 0 ) { @@ -951,6 +671,14 @@ trackContentObject * instrumentTrack::createTCO( const midiTime & ) +trackView * instrumentTrack::createView( trackContainerView * _tcv ) +{ + return( new instrumentTrackView( this, _tcv ) ); +} + + + + void instrumentTrack::saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _this ) { @@ -961,18 +689,20 @@ void instrumentTrack::saveTrackSpecificSettings( QDomDocument & _doc, m_effectChannelModel.saveSettings( _doc, _this, "fxch" ); m_baseNoteModel.saveSettings( _doc, _this, "basenote" ); - _this.setAttribute( "tab", m_tabWidget->activeTab() ); - - mainWindow::saveWidgetState( this, _this ); if( m_instrument != NULL ) { m_instrument->saveState( _doc, _this ); } - m_envWidget->saveState( _doc, _this ); - m_arpWidget->saveState( _doc, _this ); - m_midiWidget->saveState( _doc, _this ); + m_soundShaping.saveState( _doc, _this ); + m_chordCreator.saveState( _doc, _this ); + m_arpeggiator.saveState( _doc, _this ); + m_midiIO.saveState( _doc, _this ); m_audioPort.getEffects()->saveState( _doc, _this ); + if( getHook() ) + { + getHook()->saveSettings( _doc, _this ); + } } @@ -1003,33 +733,34 @@ void instrumentTrack::loadTrackSpecificSettings( const QDomElement & _this ) m_baseNoteModel.loadSettings( _this, "basenote" ); } - int tab = _this.attribute( "tab" ).toInt(); - - bool had_fx = FALSE; + m_audioPort.getEffects()->deleteAllPlugins(); QDomNode node = _this.firstChild(); while( !node.isNull() ) { if( node.isElement() ) { - if( m_envWidget->nodeName() == node.nodeName() ) + if( m_soundShaping.nodeName() == node.nodeName() ) { - m_envWidget->restoreState( node.toElement() ); + m_soundShaping.restoreState( node.toElement() ); } - else if( m_arpWidget->nodeName() == node.nodeName() ) + else if( m_chordCreator.nodeName() == node.nodeName() ) { - m_arpWidget->restoreState( node.toElement() ); + m_chordCreator.restoreState( node.toElement() ); } - else if( m_midiWidget->nodeName() == node.nodeName() ) + else if( m_arpeggiator.nodeName() == node.nodeName() ) { - m_midiWidget->restoreState( node.toElement() ); + m_arpeggiator.restoreState( node.toElement() ); + } + else if( m_midiIO.nodeName() == node.nodeName() ) + { + m_midiIO.restoreState( node.toElement() ); } else if( m_audioPort.getEffects()->nodeName() == node.nodeName() ) { m_audioPort.getEffects()->restoreState( node.toElement() ); - had_fx = TRUE; } else if( automationPattern::classNodeName() != node.nodeName() ) @@ -1037,7 +768,6 @@ void instrumentTrack::loadTrackSpecificSettings( const QDomElement & _this ) // if node-name doesn't match any known one, // we assume that it is an instrument-plugin // which we'll try to load - delete m_instrumentView; delete m_instrument; m_instrument = instrument::instantiate( node.nodeName(), this ); @@ -1047,29 +777,15 @@ void instrumentTrack::loadTrackSpecificSettings( const QDomElement & _this ) m_instrument->restoreState( node.toElement() ); } - m_instrumentView = m_instrument-> - createView( m_tabWidget ); - m_tabWidget->addTab( m_instrumentView, - tr( "PLUGIN" ), 0 ); } } node = node.nextSibling(); } - // TODO: why not move above without any condition?? - if( !had_fx ) - { - m_audioPort.getEffects()->deleteAllPlugins(); - } engine::getMixer()->unlock(); - m_tabWidget->setActiveTab( tab ); - - m_pianoWidget->update(); - - mainWindow::restoreWidgetState( this, _this ); - if( isVisible() == TRUE ) + if( getHook() ) { - m_tswInstrumentTrackButton->setChecked( TRUE ); + getHook()->loadSettings( _this ); } } @@ -1081,16 +797,11 @@ instrument * instrumentTrack::loadInstrument( const QString & _plugin_name ) invalidateAllMyNPH(); engine::getMixer()->lock(); - delete m_instrumentView; delete m_instrument; m_instrument = instrument::instantiate( _plugin_name, this ); engine::getMixer()->unlock(); - m_instrumentView = m_instrument->createView( m_tabWidget ); - m_tabWidget->addTab( m_instrumentView, tr( "PLUGIN" ), 0 ); - m_tabWidget->setActiveTab( 0 ); - - m_tswInstrumentTrackButton->update(); + emit instrumentChanged(); return( m_instrument ); } @@ -1098,20 +809,434 @@ instrument * instrumentTrack::loadInstrument( const QString & _plugin_name ) -void instrumentTrack::textChanged( const QString & _new_name ) +void instrumentTrack::invalidateAllMyNPH( void ) { - setName( _new_name ); - engine::getSongEditor()->setModified(); + engine::getMixer()->lock(); + for( int i = 0; i < NOTES; ++i ) + { + m_notes[i] = NULL; + } + + // invalidate all note-play-handles linked to this channel + m_processHandles.clear(); + engine::getMixer()->removePlayHandles( this ); + engine::getMixer()->unlock(); } -void instrumentTrack::toggledInstrumentTrackButton( bool _on ) + +// #### ITV: + +instrumentTrackView::instrumentTrackView( instrumentTrack * _it, + trackContainerView * _tcv ) : + trackView( _it, _tcv ) { - if( m_tswInstrumentTrackButton->isChecked() != _on ) + setAcceptDrops( TRUE ); + setFixedHeight( 32 ); + + // creation of widgets for track-settings-widget + m_tswVolumeKnob = new volumeKnob( knobSmall_17, + getTrackSettingsWidget(), + tr( "Volume" ) ); + m_tswVolumeKnob->setModel( &_it->m_volumeModel ); + m_tswVolumeKnob->setHintText( tr( "Volume:" ) + " ", "%" ); + m_tswVolumeKnob->move( 4, 4 ); + m_tswVolumeKnob->setLabel( tr( "VOL" ) ); + m_tswVolumeKnob->show(); + m_tswVolumeKnob->setWhatsThis( tr( volume_help ) ); + + QPushButton * tsw_midi = new QPushButton( + embed::getIconPixmap( "piano" ), QString::null, + getTrackSettingsWidget() ); + tsw_midi->setGeometry( 32, 2, 28, 28 ); + tsw_midi->show(); + toolTip::add( tsw_midi, tr( "MIDI input/output" ) ); + m_tswMidiMenu = new QMenu( tsw_midi ); + tsw_midi->setMenu( m_tswMidiMenu ); + + + m_tswActivityIndicator = new fadeButton( QColor( 96, 96, 96 ), + QColor( 255, 204, 0 ), + getTrackSettingsWidget() ); + m_tswActivityIndicator->setGeometry( 212, 2, 8, 28 ); + m_tswActivityIndicator->show(); + connect( m_tswActivityIndicator, SIGNAL( pressed( void ) ), + this, SLOT( activityIndicatorPressed() ) ); + connect( m_tswActivityIndicator, SIGNAL( released( void ) ), + this, SLOT( activityIndicatorReleased() ) ); + + + m_tswInstrumentTrackButton = new instrumentTrackButton( this ); + m_tswInstrumentTrackButton->setCheckable( TRUE ); + m_tswInstrumentTrackButton->setGeometry( 64, 2, 144, 28 ); + m_tswInstrumentTrackButton->show(); + +/* if( m_midiWidget->m_readablePorts ) { - m_tswInstrumentTrackButton->setChecked( _on ); + m_midiInputAction = m_tswMidiMenu->addMenu( + m_midiWidget->m_readablePorts ); + } + else + { + m_midiInputAction = m_tswMidiMenu->addAction( "" ); + connect( m_midiInputAction, SIGNAL( changed() ), this, + SLOT( midiInSelected() ) ); + } + if( m_midiWidget->m_writeablePorts ) + { + m_midiOutputAction = m_tswMidiMenu->addMenu( + m_midiWidget->m_writeablePorts ); + } + else + { + m_midiOutputAction = m_tswMidiMenu->addAction( "" ); + connect( m_midiOutputAction, SIGNAL( changed() ), this, + SLOT( midiOutSelected() ) ); + } + m_midiInputAction->setText( tr( "MIDI input" ) ); + m_midiOutputAction->setText( tr( "MIDI output" ) ); + if( m_midiWidget->m_readablePorts == NULL || + m_midiWidget->m_writeablePorts == NULL ) + { + connect( m_midiWidget->m_sendCheckBox, + SIGNAL( toggled( bool ) ), + this, SLOT( midiConfigChanged( bool ) ) ); + connect( m_midiWidget->m_receiveCheckBox, + SIGNAL( toggled( bool ) ), + this, SLOT( midiConfigChanged( bool ) ) ); + }*/ + + setModel( _it ); + + m_window = new instrumentTrackWindow( this ); + connect( m_tswInstrumentTrackButton, SIGNAL( toggled( bool ) ), + m_window, SLOT( toggledInstrumentTrackButton( bool ) ) ); + +} + + + + +instrumentTrackView::~instrumentTrackView() +{ + delete m_window; +} + + + + +void instrumentTrackView::activityIndicatorPressed( void ) +{ + model()->processInEvent( midiEvent( NOTE_ON, 0, + DEFAULT_OCTAVE * NOTES_PER_OCTAVE + A, + 127 ), midiTime() ); +} + + + + +void instrumentTrackView::activityIndicatorReleased( void ) +{ + model()->processInEvent( midiEvent( NOTE_OFF, 0, + DEFAULT_OCTAVE * NOTES_PER_OCTAVE + A, + 0 ), midiTime() ); +} + + + + + +void instrumentTrackView::updateName( void ) +{ +#ifdef LMMS_DEBUG + assert( m_tswInstrumentTrackButton != NULL ); +#endif + m_tswInstrumentTrackButton->setText( model()->name() ); +} + + + + + + + +// #### ITW: +instrumentTrackWindow::instrumentTrackWindow( instrumentTrackView * _itv ) : + QWidget(), + modelView( NULL ), + m_track( _itv->model() ), + m_itv( _itv ), + m_instrumentView( NULL ), + m_midiInputAction( NULL ), + m_midiOutputAction( NULL ) +{ + setAcceptDrops( TRUE ); + + // init own layout + widgets + setFocusPolicy( Qt::StrongFocus ); + QVBoxLayout * vlayout = new QVBoxLayout( this ); + vlayout->setMargin( 0 ); + vlayout->setSpacing( 0 ); + + m_generalSettingsWidget = new tabWidget( tr( "GENERAL SETTINGS" ), + this ); + m_generalSettingsWidget->setFixedHeight( 90 ); + + // setup line-edit for changing channel-name + m_instrumentNameLE = new QLineEdit( m_generalSettingsWidget ); + m_instrumentNameLE->setFont( pointSize<8>( + m_instrumentNameLE->font() ) ); + m_instrumentNameLE->setGeometry( 10, 16, 230, 18 ); + connect( m_instrumentNameLE, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged( const QString & ) ) ); + + + // setup volume-knob + m_volumeKnob = new volumeKnob( knobBright_26, m_generalSettingsWidget, + tr( "Channel volume" ) ); + m_volumeKnob->move( 10, 44 ); + m_volumeKnob->setHintText( tr( "Channel volume:" ) + " ", "%" ); + m_volumeKnob->setLabel( tr( "VOLUME" ) ); + + m_volumeKnob->setWhatsThis( tr( volume_help ) ); + + + // setup surround-area + m_surroundArea = new surroundArea( m_generalSettingsWidget, + tr( "Surround area" ) ); + m_surroundArea->move( 20 + m_volumeKnob->width(), 38 ); + m_surroundArea->show(); + m_surroundArea->setWhatsThis( tr( surroundarea_help ) ); + + + // setup spinbox for selecting FX-channel + m_effectChannelNumber = new lcdSpinBox( 2, m_generalSettingsWidget, + tr( "FX channel" ) ); + m_effectChannelNumber->setLabel( tr( "FX CHNL" ) ); + m_effectChannelNumber->move( m_surroundArea->x() + + m_surroundArea->width() + 16, 40 ); + + + m_saveSettingsBtn = new QPushButton( embed::getIconPixmap( + "project_save" ), "", + m_generalSettingsWidget ); + m_saveSettingsBtn->setGeometry( m_effectChannelNumber->x() + + m_effectChannelNumber->width() + 20, 40, + 32, 32 ); + connect( m_saveSettingsBtn, SIGNAL( clicked() ), this, + SLOT( saveSettingsBtnClicked() ) ); + toolTip::add( m_saveSettingsBtn, + tr( "Save current channel settings in a preset-file" ) ); + m_saveSettingsBtn->setWhatsThis( + tr( "Click here, if you want to save current channel settings " + "in a preset-file. Later you can load this preset by " + "double-clicking it in the preset-browser." ) ); + + + m_tabWidget = new tabWidget( "", this ); + m_tabWidget->setFixedHeight( INSTRUMENT_HEIGHT + 12 ); + + + // create tab-widgets + m_ssView = new instrumentSoundShapingView( m_tabWidget ); + QWidget * instrument_functions = new QWidget( m_tabWidget ); + m_chordView = new chordCreatorView( &m_track->m_chordCreator, + instrument_functions ); + m_arpView= new arpeggiatorView( &m_track->m_arpeggiator, + instrument_functions ); + m_midiView = new instrumentMidiIOView( m_tabWidget ); + m_effectView = new effectRackView( m_track->m_audioPort.getEffects(), + m_tabWidget ); + m_tabWidget->addTab( m_ssView, tr( "ENV/LFO" ), 1 ); + m_tabWidget->addTab( instrument_functions, tr( "FUNC" ), 2 ); + m_tabWidget->addTab( m_effectView, tr( "FX" ), 3 ); + m_tabWidget->addTab( m_midiView, tr( "MIDI" ), 4 ); + + // setup piano-widget + m_pianoView= new pianoView( this ); + m_pianoView->setFixedSize( INSTRUMENT_WIDTH, PIANO_HEIGHT ); + + vlayout->addWidget( m_generalSettingsWidget ); + vlayout->addWidget( m_tabWidget ); + vlayout->addWidget( m_pianoView ); + + if( m_midiView->m_readablePorts ) + { + m_midiInputAction = m_itv->m_tswMidiMenu->addMenu( + m_midiView->m_readablePorts ); + } + else + { + m_midiInputAction = m_itv->m_tswMidiMenu->addAction( "" ); + connect( m_midiInputAction, SIGNAL( changed() ), this, + SLOT( midiInSelected() ) ); + } + if( m_midiView->m_writeablePorts ) + { + m_midiOutputAction = m_itv->m_tswMidiMenu->addMenu( + m_midiView->m_writeablePorts ); + } + else + { + m_midiOutputAction = m_itv->m_tswMidiMenu->addAction( "" ); + connect( m_midiOutputAction, SIGNAL( changed() ), this, + SLOT( midiOutSelected() ) ); + } + m_midiInputAction->setText( tr( "MIDI input" ) ); + m_midiOutputAction->setText( tr( "MIDI output" ) ); + if( m_midiView->m_readablePorts == NULL || + m_midiView->m_writeablePorts == NULL ) + { + connect( m_midiView->m_sendCheckBox, + SIGNAL( toggled( bool ) ), + this, SLOT( midiConfigChanged( bool ) ) ); + connect( m_midiView->m_receiveCheckBox, + SIGNAL( toggled( bool ) ), + this, SLOT( midiConfigChanged( bool ) ) ); + } + + setModel( _itv->model() ); + + // set window-icon + setWindowIcon( embed::getIconPixmap( "instrument_track" ) ); + + updateInstrumentView(); + + setFixedWidth( INSTRUMENT_WIDTH ); + resize( sizeHint() ); + + if( engine::getMainWindow()->workspace() ) + { + engine::getMainWindow()->workspace()->addSubWindow( this ); + parentWidget()->hide(); + } + else + { + hide(); + } +} + + + + +instrumentTrackWindow::~instrumentTrackWindow() +{ + if( engine::getMainWindow()->workspace() ) + { + parentWidget()->hide(); + parentWidget()->deleteLater(); + } +} + + + + +void instrumentTrackWindow::modelChanged( void ) +{ + m_track = m_itv->model(); + + m_instrumentNameLE->setText( m_track->name() ); + connect( m_track, SIGNAL( nameChanged() ), + this, SLOT( updateName() ) ); + connect( m_track, SIGNAL( instrumentChanged() ), + this, SLOT( updateInstrumentView() ), + Qt::QueuedConnection ); + m_volumeKnob->setModel( &m_track->m_volumeModel ); + m_surroundArea->setModel( &m_track->m_surroundAreaModel ); + m_pianoView->setModel( &m_track->m_piano ); + + m_ssView->setModel( &m_track->m_soundShaping ); + m_chordView->setModel( &m_track->m_chordCreator ); + m_arpView->setModel( &m_track->m_arpeggiator ); + m_midiView->setModel( &m_track->m_midiIO ); + updateName(); +} + + + + +void instrumentTrackWindow::saveSettingsBtnClicked( void ) +{ + QFileDialog sfd( this, tr( "Save channel-settings in file" ), "", + tr( "Channel-Settings-File (*.cs.xml)" ) ); + + QString preset_root = configManager::inst()->userPresetsDir(); + if( !QDir( preset_root ).exists() ) + { + QDir().mkdir( preset_root ); + } + if( !QDir( preset_root + m_track->instrumentName() ).exists() ) + { + QDir( preset_root ).mkdir( m_track->instrumentName() ); + } + + sfd.setDirectory( preset_root + m_track->instrumentName() ); + sfd.setFileMode( QFileDialog::AnyFile ); + if( sfd.exec () == QDialog::Accepted && + !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" + ) + { + multimediaProject mmp( + multimediaProject::InstrumentTrackSettings ); + QDomElement _this = mmp.createElement( m_track->nodeName() ); + m_track->saveTrackSpecificSettings( mmp, _this ); + mmp.content().appendChild( _this ); + QString f = sfd.selectedFiles()[0]; + mmp.writeFile( f ); + } +} + + + + + +void instrumentTrackWindow::updateName( void ) +{ + setWindowTitle( m_track->name() ); + + if( m_instrumentNameLE->text() != m_track->name() ) + { + m_instrumentNameLE->setText( m_track->name() ); + } +} + + + + + +void instrumentTrackWindow::updateInstrumentView( void ) +{ + delete m_instrumentView; + if( m_track->m_instrument != NULL ) + { + m_instrumentView = m_track->m_instrument->createView( + m_tabWidget ); + m_tabWidget->addTab( m_instrumentView, tr( "PLUGIN" ), 0 ); + m_tabWidget->setActiveTab( 0 ); + } + +// m_tswInstrumentTrackButton->update(); +} + + + + +void instrumentTrackWindow::textChanged( const QString & _new_name ) +{ + m_track->setName( _new_name ); + engine::getSong()->setModified(); +} + + + + +void instrumentTrackWindow::toggledInstrumentTrackButton( bool _on ) +{ + if( m_itv->m_tswInstrumentTrackButton->isChecked() != _on ) + { + m_itv->m_tswInstrumentTrackButton->setChecked( _on ); } if( _on ) { @@ -1143,7 +1268,7 @@ void instrumentTrack::toggledInstrumentTrackButton( bool _on ) -void instrumentTrack::closeEvent( QCloseEvent * _ce ) +void instrumentTrackWindow::closeEvent( QCloseEvent * _ce ) { _ce->ignore(); if( engine::getMainWindow()->workspace() ) @@ -1154,21 +1279,21 @@ void instrumentTrack::closeEvent( QCloseEvent * _ce ) { hide(); } - m_tswInstrumentTrackButton->setChecked( FALSE ); + m_itv->m_tswInstrumentTrackButton->setChecked( FALSE ); } -void instrumentTrack::focusInEvent( QFocusEvent * ) +void instrumentTrackWindow::focusInEvent( QFocusEvent * ) { - m_pianoWidget->setFocus(); + m_pianoView->setFocus(); } -void instrumentTrack::dragEnterEvent( QDragEnterEvent * _dee ) +void instrumentTrackWindow::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, "instrument,presetfile" ); } @@ -1176,22 +1301,22 @@ void instrumentTrack::dragEnterEvent( QDragEnterEvent * _dee ) -void instrumentTrack::dropEvent( QDropEvent * _de ) +void instrumentTrackWindow::dropEvent( QDropEvent * _de ) { QString type = stringPairDrag::decodeKey( _de ); QString value = stringPairDrag::decodeValue( _de ); if( type == "instrument" ) { - loadInstrument( value ); - engine::getSongEditor()->setModified(); + m_track->loadInstrument( value ); + engine::getSong()->setModified(); _de->accept(); } else if( type == "presetfile" ) { multimediaProject mmp( value ); - loadTrackSpecificSettings( mmp.content().firstChild(). + m_track->loadTrackSpecificSettings( mmp.content().firstChild(). toElement() ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); _de->accept(); } } @@ -1199,18 +1324,53 @@ void instrumentTrack::dropEvent( QDropEvent * _de ) -void instrumentTrack::invalidateAllMyNPH( void ) +void instrumentTrackWindow::saveSettings( QDomDocument & _doc, + QDomElement & _this ) { - engine::getMixer()->lock(); - for( int i = 0; i < NOTES; ++i ) - { - m_notes[i] = NULL; - } + _this.setAttribute( "tab", m_tabWidget->activeTab() ); + mainWindow::saveWidgetState( this, _this ); +} - // invalidate all note-play-handles linked to this channel - m_processHandles.clear(); - engine::getMixer()->removePlayHandles( this ); - engine::getMixer()->unlock(); + + + +void instrumentTrackWindow::loadSettings( const QDomElement & _this ) +{ + m_tabWidget->setActiveTab( _this.attribute( "tab" ).toInt() ); + mainWindow::restoreWidgetState( this, _this ); + if( isVisible() ) + { + m_itv->m_tswInstrumentTrackButton->setChecked( TRUE ); + } +} + + + +void instrumentTrackWindow::midiInSelected( void ) +{ + m_midiInputAction->setChecked( !m_midiInputAction->isChecked() ); + m_midiView->m_receiveCheckBox->setChecked( + m_midiInputAction->isChecked() ); +} + + + +void instrumentTrackWindow::midiOutSelected( void ) +{ + m_midiOutputAction->setChecked( !m_midiOutputAction->isChecked() ); + m_midiView->m_sendCheckBox->setChecked( + m_midiOutputAction->isChecked() ); +} + + + + +void instrumentTrackWindow::midiConfigChanged( bool ) +{ + m_midiInputAction->setChecked( + m_midiView->m_receiveCheckBox->model()->value() ); + m_midiOutputAction->setChecked( + m_midiView->m_sendCheckBox->model()->value() ); } @@ -1218,13 +1378,9 @@ void instrumentTrack::invalidateAllMyNPH( void ) - - - -instrumentTrackButton::instrumentTrackButton( instrumentTrack * - _instrument_track ) : - QPushButton( _instrument_track->getTrackSettingsWidget() ), - m_instrumentTrack( _instrument_track ) +instrumentTrackButton::instrumentTrackButton( instrumentTrackView * _itv ) : + QPushButton( _itv->getTrackSettingsWidget() ), + m_instrumentTrackView( _itv ) { setAcceptDrops( TRUE ); } @@ -1239,19 +1395,22 @@ instrumentTrackButton::~instrumentTrackButton() -void instrumentTrackButton::drawButtonLabel( QPainter * _p ) +void instrumentTrackButton::paintEvent( QPaintEvent * _pe ) { - QString in = m_instrumentTrack->instrumentName() + ":"; + QPushButton::paintEvent( _pe ); + QPainter p( this ); + const QString in = m_instrumentTrackView->model()->instrumentName() + + ":"; + const QString n = m_instrumentTrackView->model()->name(); int extra = isChecked() ? -1 : -3; - _p->setFont( pointSize<7>( _p->font() ) ); - _p->setPen( QApplication::palette().buttonText().color() ); - _p->drawText( ( width() - QFontMetrics( _p->font() ).width( in ) ) / 2 + + p.setFont( pointSize<7>( p.font() ) ); + p.setPen( QApplication::palette().buttonText().color() ); + p.drawText( ( width() - QFontMetrics( p.font() ).width( in ) ) / 2 + extra, height() / 2 + extra, in ); - _p->setPen( QColor( 0, 0, 0 ) ); - _p->drawText( ( width() - QFontMetrics( _p->font() ).width( text() ) ) / + p.setPen( QColor( 0, 0, 0 ) ); + p.drawText( ( width() - QFontMetrics( p.font() ).width( n ) ) / 2 + extra, height() / 2 + - QFontMetrics( _p->font() ).height() + extra, - text() ); + QFontMetrics( p.font() ).height() + extra, n ); } @@ -1259,7 +1418,7 @@ void instrumentTrackButton::drawButtonLabel( QPainter * _p ) void instrumentTrackButton::dragEnterEvent( QDragEnterEvent * _dee ) { - m_instrumentTrack->dragEnterEvent( _dee ); + m_instrumentTrackView->m_window->dragEnterEvent( _dee ); } @@ -1267,12 +1426,13 @@ void instrumentTrackButton::dragEnterEvent( QDragEnterEvent * _dee ) void instrumentTrackButton::dropEvent( QDropEvent * _de ) { - m_instrumentTrack->dropEvent( _de ); + m_instrumentTrackView->m_window->dropEvent( _de ); setChecked( TRUE ); } + #include "instrument_track.moc" diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index c2ea2abf39..ddad35a4b2 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -3,7 +3,7 @@ /* * pattern.cpp - implementation of class pattern which holds notes * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * Copyright (c) 2005-2007 Danny McRae * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -46,27 +47,25 @@ #include "rename_dialog.h" #include "sample_buffer.h" #include "audio_sample_recorder.h" -#include "song_editor.h" +#include "song.h" #include "tooltip.h" #include "bb_editor.h" #include "string_pair_drag.h" #include "main_window.h" -QPixmap * pattern::s_stepBtnOn = NULL; -QPixmap * pattern::s_stepBtnOverlay = NULL; -QPixmap * pattern::s_stepBtnOff = NULL; -QPixmap * pattern::s_stepBtnOffLight = NULL; -QPixmap * pattern::s_frozen = NULL; +QPixmap * patternView::s_stepBtnOn = NULL; +QPixmap * patternView::s_stepBtnOverlay = NULL; +QPixmap * patternView::s_stepBtnOff = NULL; +QPixmap * patternView::s_stepBtnOffLight = NULL; +QPixmap * patternView::s_frozen = NULL; -pattern::pattern ( instrumentTrack * _instrument_track ) : +pattern::pattern( instrumentTrack * _instrument_track ) : trackContentObject( _instrument_track ), - m_paintPixmap(), - m_needsUpdate( TRUE ), m_instrumentTrack( _instrument_track ), - m_patternType( BEAT_PATTERN ), + m_patternType( BeatPattern ), m_name( _instrument_track->name() ), m_steps( DEFAULT_STEPS_PER_TACT ), m_frozenPattern( NULL ), @@ -81,8 +80,6 @@ pattern::pattern ( instrumentTrack * _instrument_track ) : pattern::pattern( const pattern & _pat_to_copy ) : trackContentObject( _pat_to_copy.m_instrumentTrack ), - m_paintPixmap(), - m_needsUpdate( TRUE ), m_instrumentTrack( _pat_to_copy.m_instrumentTrack ), m_patternType( _pat_to_copy.m_patternType ), m_name( "" ), @@ -104,19 +101,6 @@ pattern::pattern( const pattern & _pat_to_copy ) : pattern::~pattern() { - if( engine::getPianoRoll()->currentPattern() == this ) - { - engine::getPianoRoll()->setCurrentPattern( NULL ); - // we have to have the song-editor to stop playing if it played - // us before - if( engine::getSongEditor()->playing() && - engine::getSongEditor()->playMode() == - songEditor::PLAY_PATTERN ) - { - engine::getSongEditor()->playPattern( NULL ); - } - } - for( noteVector::iterator it = m_notes.begin(); it != m_notes.end(); ++it ) { @@ -136,48 +120,12 @@ pattern::~pattern() void pattern::init( void ) { - if( s_stepBtnOn == NULL ) - { - s_stepBtnOn = new QPixmap( embed::getIconPixmap( - "step_btn_on_100" ) ); - } - - if( s_stepBtnOverlay == NULL ) - { - s_stepBtnOverlay = new QPixmap( embed::getIconPixmap( - "step_btn_on_yellow" ) ); - } - - if( s_stepBtnOff == NULL ) - { - s_stepBtnOff = new QPixmap( embed::getIconPixmap( - "step_btn_off" ) ); - } - - if( s_stepBtnOffLight == NULL ) - { - s_stepBtnOffLight = new QPixmap( embed::getIconPixmap( - "step_btn_off_light" ) ); - } - - if( s_frozen == NULL ) - { - s_frozen = new QPixmap( embed::getIconPixmap( "frozen" ) ); - } - saveJournallingState( FALSE ); ensureBeatNotes(); changeLength( length() ); restoreJournallingState(); - - setFixedHeight( parentWidget()->height() - 2 ); - setAutoResizeEnabled( FALSE ); - - toolTip::add( this, - tr( "double-click to open this pattern in piano-roll\n" - "use mouse wheel to set volume of a step" ) ); } @@ -185,7 +133,7 @@ void pattern::init( void ) midiTime pattern::length( void ) const { - if( m_patternType == BEAT_PATTERN ) + if( m_patternType == BeatPattern ) { if( m_steps % DEFAULT_STEPS_PER_TACT == 0 ) { @@ -217,7 +165,7 @@ midiTime pattern::length( void ) const note * pattern::addNote( const note & _new_note, const bool _quant_pos ) { note * new_note = new note( _new_note ); - if( _quant_pos ) + if( _quant_pos && engine::getPianoRoll() ) { new_note->quantizePos( engine::getPianoRoll()->quantization() ); } @@ -248,9 +196,10 @@ note * pattern::addNote( const note & _new_note, const bool _quant_pos ) engine::getMixer()->unlock(); checkType(); - update(); changeLength( length() ); + emit dataChanged(); + updateBBTrack(); return( new_note ); @@ -276,9 +225,10 @@ void pattern::removeNote( const note * _note_to_del ) engine::getMixer()->unlock(); checkType(); - update(); changeLength( length() ); + emit dataChanged(); + updateBBTrack(); } @@ -311,20 +261,16 @@ void pattern::clearNotes( void ) engine::getMixer()->unlock(); checkType(); - update(); - if( engine::getPianoRoll()->currentPattern() == this ) - { - engine::getPianoRoll()->update(); - } + emit dataChanged(); } -void pattern::setType( patternTypes _new_pattern_type ) +void pattern::setType( PatternTypes _new_pattern_type ) { - if( _new_pattern_type == BEAT_PATTERN || - _new_pattern_type == MELODY_PATTERN ) + if( _new_pattern_type == BeatPattern || + _new_pattern_type == MelodyPattern ) { m_patternType = _new_pattern_type; } @@ -340,12 +286,12 @@ void pattern::checkType( void ) { if( ( *it )->length() > 0 ) { - setType( pattern::MELODY_PATTERN ); + setType( pattern::MelodyPattern ); return; } ++it; } - setType( pattern::BEAT_PATTERN ); + setType( pattern::BeatPattern ); } @@ -390,7 +336,7 @@ void pattern::loadSettings( const QDomElement & _this ) { unfreeze(); - m_patternType = static_cast( _this.attribute( "type" + m_patternType = static_cast( _this.attribute( "type" ).toInt() ); m_name = _this.attribute( "name" ); if( _this.attribute( "pos" ).toInt() >= 0 ) @@ -430,39 +376,14 @@ void pattern::loadSettings( const QDomElement & _this ) { freeze(); }*/ - update(); + + emit dataChanged(); + updateBBTrack(); } -void pattern::update( void ) -{ - m_needsUpdate = TRUE; - changeLength( length() ); - trackContentObject::update(); -} - - - - -void pattern::openInPianoRoll( void ) -{ - openInPianoRoll( FALSE ); -} - - - - -void pattern::openInPianoRoll( bool ) -{ - engine::getPianoRoll()->setCurrentPattern( this ); - engine::getPianoRoll()->parentWidget()->show(); - engine::getPianoRoll()->setFocus(); -} - - - void pattern::clear( void ) { @@ -473,26 +394,9 @@ void pattern::clear( void ) -void pattern::resetName( void ) -{ - m_name = m_instrumentTrack->name(); -} - - - - -void pattern::changeName( void ) -{ - renameDialog rename_dlg( m_name ); - rename_dlg.exec(); -} - - - - void pattern::freeze( void ) { - if( engine::getSongEditor()->playing() ) + if( engine::getSong()->playing() ) { QMessageBox::information( 0, tr( "Cannot freeze pattern" ), tr( "The pattern currently " @@ -524,7 +428,7 @@ void pattern::unfreeze( void ) { sharedObject::unref( m_frozenPattern ); m_frozenPattern = NULL; - update(); + emit dataChanged(); } } @@ -539,28 +443,11 @@ void pattern::abortFreeze( void ) -void pattern::addSteps( QAction * _item ) -{ - addSteps( _item->text().toInt() ); -} - - - - -void pattern::removeSteps( QAction * _item ) -{ - removeSteps( _item->text().toInt() ); -} - - - - - void pattern::addSteps( int _n ) { m_steps += _n; ensureBeatNotes(); - update(); + emit dataChanged(); } @@ -584,409 +471,21 @@ void pattern::removeSteps( int _n ) } } m_steps -= _n; - update(); + emit dataChanged(); } } -void pattern::constructContextMenu( QMenu * _cm ) +trackContentObjectView * pattern::createView( trackView * _tv ) { - QAction * a = new QAction( embed::getIconPixmap( "piano" ), - tr( "Open in piano-roll" ), _cm ); - _cm->insertAction( _cm->actions()[0], a ); - connect( a, SIGNAL( triggered( bool ) ), this, - SLOT( openInPianoRoll( bool ) ) ); - _cm->insertSeparator( _cm->actions()[1] ); - - _cm->addSeparator(); - - _cm->addAction( embed::getIconPixmap( "edit_erase" ), - tr( "Clear all notes" ), this, SLOT( clear() ) ); - _cm->addSeparator(); - - _cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ), - this, SLOT( resetName() ) ); - _cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ), - this, SLOT( changeName() ) ); - _cm->addSeparator(); - - bool freeze_separator = FALSE; - if( !( m_instrumentTrack->muted() || muted() ) ) - { - _cm->addAction( embed::getIconPixmap( "freeze" ), - m_frozenPattern ? tr( "Refreeze" ) : tr( "Freeze" ), - this, SLOT( freeze() ) ); - freeze_separator = TRUE; - } - if( m_frozenPattern ) - { - _cm->addAction( embed::getIconPixmap( "unfreeze" ), - tr( "Unfreeze" ), this, SLOT( unfreeze() ) ); - freeze_separator = TRUE; - } - if( freeze_separator ) - { - _cm->addSeparator(); - } - - QMenu * add_step_menu = _cm->addMenu( - embed::getIconPixmap( "step_btn_add" ), - tr( "Add steps" ) ); - QMenu * remove_step_menu = _cm->addMenu( - embed::getIconPixmap( "step_btn_remove" ), - tr( "Remove steps" ) ); - connect( add_step_menu, SIGNAL( triggered( QAction * ) ), - this, SLOT( addSteps( QAction * ) ) ); - connect( remove_step_menu, SIGNAL( triggered( QAction * ) ), - this, SLOT( removeSteps( QAction * ) ) ); - for( int i = 1; i <= 16; i *= 2 ) - { - const QString label = ( i == 1 ) ? - tr( "1 step" ) : - tr( "%1 steps" ).arg( i ); - add_step_menu->addAction( label ); - remove_step_menu->addAction( label ); - } + return( new patternView( this, _tv ) ); } -void pattern::mouseDoubleClickEvent( QMouseEvent * _me ) -{ - if( _me->button() != Qt::LeftButton ) - { - _me->ignore(); - return; - } - if( m_patternType == pattern::MELODY_PATTERN || - !( m_patternType == pattern::BEAT_PATTERN && - ( pixelsPerTact() >= 192 || - m_steps != DEFAULT_STEPS_PER_TACT ) && - _me->y() > height() - s_stepBtnOff->height() ) ) - { - openInPianoRoll(); - } -} - - - - -void pattern::mousePressEvent( QMouseEvent * _me ) -{ - if( _me->button() == Qt::LeftButton && - m_patternType == pattern::BEAT_PATTERN && - ( fixedTCOs() || pixelsPerTact() >= 192 || - m_steps != DEFAULT_STEPS_PER_TACT ) && - _me->y() > height() - s_stepBtnOff->height() ) - { - int step = ( _me->x() - TCO_BORDER_WIDTH ) * - length() / BEATS_PER_TACT / width(); - if( step >= m_steps ) - { - return; - } - note * n = m_notes[step]; - if( n->length() < 0 ) - { - n->setLength( 0 ); - } - else - { - n->setLength( -64 ); - } - engine::getSongEditor()->setModified(); - update(); - if( engine::getPianoRoll()->currentPattern() == this ) - { - engine::getPianoRoll()->update(); - } - } - else if( m_frozenPattern != NULL && _me->button() == Qt::LeftButton && - engine::getMainWindow()->isShiftPressed() == TRUE ) - { - QString s; - new stringPairDrag( "sampledata", - m_frozenPattern->toBase64( s ), - embed::getIconPixmap( "freeze" ), - this ); - } - else - { - trackContentObject::mousePressEvent( _me ); - } -} - - - - -void pattern::wheelEvent( QWheelEvent * _we ) -{ - if( m_patternType == pattern::BEAT_PATTERN && - ( fixedTCOs() || pixelsPerTact() >= 192 || - m_steps != DEFAULT_STEPS_PER_TACT ) && - _we->y() > height() - s_stepBtnOff->height() ) - { - int step = ( _we->x() - TCO_BORDER_WIDTH ) * - length() / BEATS_PER_TACT / width(); - if( step >= m_steps ) - { - return; - } - note * n = m_notes[step]; - Uint8 vol = n->getVolume(); - - if( n->length() == 0 && _we->delta() > 0 ) - { - n->setLength( -64 ); - n->setVolume( 5 ); - } - else if( _we->delta() > 0 ) - { - if( vol < 95 ) - { - n->setVolume( vol + 5 ); - } - } - else - { - if( vol > 5 ) - { - n->setVolume( vol - 5 ); - } - else - { - n->setLength( 0 ); - } - } - engine::getSongEditor()->setModified(); - update(); - if( engine::getPianoRoll()->currentPattern() == this ) - { - engine::getPianoRoll()->update(); - } - _we->accept(); - } - else - { - trackContentObject::wheelEvent( _we ); - } -} - - - - -void pattern::paintEvent( QPaintEvent * ) -{ - if( m_needsUpdate == FALSE ) - { - QPainter p( this ); - p.drawPixmap( 0, 0, m_paintPixmap ); - return; - } - - changeLength( length() ); - - m_needsUpdate = FALSE; - - if( m_paintPixmap.isNull() == TRUE || m_paintPixmap.size() != size() ) - { - m_paintPixmap = QPixmap( size() ); - } - - QPainter p( &m_paintPixmap ); - - QLinearGradient lingrad( 0, 0, 0, height() ); - const QColor c = isSelected() ? QColor( 0, 0, 224 ) : - QColor( 96, 96, 96 ); - lingrad.setColorAt( 0, c ); - lingrad.setColorAt( 0.5, Qt::black ); - lingrad.setColorAt( 1, c ); - p.fillRect( QRect( 1, 1, width() - 2, height() - 2 ), lingrad ); - - p.setPen( QColor( 57, 69, 74 ) ); - p.drawLine( 0, 0, width(), 0 ); - p.drawLine( 0, 0, 0, height() ); - p.setPen( QColor( 120, 130, 140 ) ); - p.drawLine( 0, height() - 1, width() - 1, height() - 1 ); - p.drawLine( width() - 1, 0, width() - 1, height() - 1 ); - - p.setPen( QColor( 0, 0, 0 ) ); - p.drawRect( 1, 1, width() - 2, height() - 2 ); - - const float ppt = fixedTCOs() ? - ( parentWidget()->width() - 2 * TCO_BORDER_WIDTH ) - / (float)length().getTact() : - pixelsPerTact(); - - if( m_patternType == pattern::MELODY_PATTERN ) - { - Sint32 central_key = 0; - if( m_notes.size() > 0 ) - { - // first determine the central tone so that we can - // display the area where most of the m_notes are - Sint32 total_notes = 0; - for( noteVector::iterator it = m_notes.begin(); - it != m_notes.end(); ++it ) - { - if( ( *it )->length() > 0 ) - { - central_key += ( *it )->key(); - ++total_notes; - } - } - - if( total_notes > 0 ) - { - central_key = central_key / total_notes; - - Sint16 central_y = height() / 2; - Sint16 y_base = central_y + TCO_BORDER_WIDTH -1; - - const Sint16 x_base = TCO_BORDER_WIDTH; - - p.setPen( QColor( 0, 0, 0 ) ); - for( tact tact_num = 1; tact_num < - length().getTact(); ++tact_num ) - { - p.drawLine( - x_base + static_cast( - ppt * tact_num ) - 1, - TCO_BORDER_WIDTH, - x_base + static_cast( - ppt * tact_num ) - 1, - height() - 2 * - TCO_BORDER_WIDTH ); - } - if( getTrack()->muted() || muted() ) - { - p.setPen( QColor( 160, 160, 160 ) ); - } - else if( m_frozenPattern != NULL ) - { - p.setPen( QColor( 0x00, 0xE0, 0xFF ) ); - } - else - { - p.setPen( QColor( 0xFF, 0xB0, 0x00 ) ); - } - - for( noteVector::iterator it = m_notes.begin(); - it != m_notes.end(); ++it ) - { - Sint8 y_pos = central_key - - ( *it )->key(); - - if( ( *it )->length() > 0 && - y_pos > -central_y && - y_pos < central_y ) - { - Sint16 x1 = 2 * x_base + - static_cast( ( *it )->pos() * ppt / 64 ); - Sint16 x2 = x1 + - static_cast( ( *it )->length() * ppt / 64 ); - p.drawLine( x1, y_base + y_pos, - x2, y_base + y_pos ); - - } - } - } - } - } - else if( m_patternType == pattern::BEAT_PATTERN && - ( fixedTCOs() || ppt >= 96 - || m_steps != DEFAULT_STEPS_PER_TACT ) ) - { - QPixmap stepon; - QPixmap stepoverlay; - QPixmap stepoff; - QPixmap stepoffl; - const int steps = length() / BEATS_PER_TACT; - const int w = width() - 2 * TCO_BORDER_WIDTH; - stepon = s_stepBtnOn->scaled( w / steps, - s_stepBtnOn->height(), - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation ); - stepoverlay = s_stepBtnOverlay->scaled( w / steps, - s_stepBtnOn->height(), - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation ); - stepoff = s_stepBtnOff->scaled( w / steps, - s_stepBtnOff->height(), - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation ); - stepoffl = s_stepBtnOffLight->scaled( w / steps, - s_stepBtnOffLight->height(), - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation ); - for( noteVector::iterator it = m_notes.begin(); - it != m_notes.end(); ++it ) - { - Sint16 no = ( *it )->pos() / 4; - Sint16 x = TCO_BORDER_WIDTH + static_cast( no * - w / steps ); - Sint16 y = height() - s_stepBtnOff->height() - 1; - - Uint8 vol = ( *it )->getVolume(); - - if( ( *it )->length() < 0 ) - { - p.drawPixmap( x, y, stepoff ); - for( int i = 0; i < vol / 5 + 1; ++i ) - { - p.drawPixmap( x, y, stepon ); - } - for( int i = 0; i < ( 25 + ( vol - 75 ) ) / 5; - ++i ) - { - p.drawPixmap( x, y, stepoverlay ); - } - } - else if( ( no / BEATS_PER_TACT ) % 2 ) - { - p.drawPixmap( x, y, stepoff ); - } - else - { - p.drawPixmap( x, y, stepoffl ); - } - } - } - - p.setFont( pointSize<7>( p.font() ) ); - if( muted() || getTrack()->muted() ) - { - p.setPen( QColor( 192, 192, 192 ) ); - } - else - { - p.setPen( QColor( 32, 240, 32 ) ); - } - p.drawText( 2, p.fontMetrics().height() - 1, m_name ); - if( muted() ) - { - p.drawPixmap( 3, p.fontMetrics().height() + 1, - embed::getIconPixmap( "muted", 16, 16 ) ); - } - else if( m_frozenPattern != NULL ) - { - p.setPen( QColor( 0, 224, 255 ) ); - p.drawRect( 0, 0, width(), height() - 1 ); - p.drawPixmap( 3, height() - s_frozen->height() - 4, *s_frozen ); - } - - p.end(); - - p.begin( this ); - p.drawPixmap( 0, 0, m_paintPixmap ); - -} - - - void pattern::ensureBeatNotes( void ) { @@ -1017,9 +516,9 @@ void pattern::ensureBeatNotes( void ) void pattern::updateBBTrack( void ) { - if( getTrack()->getTrackContainer() == engine::getBBEditor() ) + if( getTrack()->getTrackContainer() == engine::getBBTrackContainer() ) { - engine::getBBEditor()->updateBBTrack( this ); + engine::getBBTrackContainer()->updateBBTrack( this ); } } @@ -1150,7 +649,6 @@ patternFreezeThread::patternFreezeThread( pattern * _pattern ) : patternFreezeThread::~patternFreezeThread() { - m_pattern->update(); } @@ -1171,9 +669,9 @@ void patternFreezeThread::run( void ) engine::getMixer()->highQuality() ); // prepare stuff for playing correct things later - engine::getSongEditor()->playPattern( m_pattern, FALSE ); - songEditor::playPos & ppp = engine::getSongEditor()->getPlayPos( - songEditor::PLAY_PATTERN ); + engine::getSong()->playPattern( m_pattern, FALSE ); + song::playPos & ppp = engine::getSong()->getPlayPos( + song::Mode_PlayPattern ); ppp.setTact( 0 ); ppp.setTact64th( 0 ); ppp.setCurrentFrame( 0 ); @@ -1202,7 +700,7 @@ void patternFreezeThread::run( void ) m_pattern->m_freezing = FALSE; // reset song-editor settings - engine::getSongEditor()->stop(); + engine::getSong()->stop(); ppp.m_timeLineUpdate = TRUE; // create final sample-buffer if freezing was successful @@ -1223,6 +721,539 @@ void patternFreezeThread::run( void ) +patternView::patternView( pattern * _pattern, trackView * _parent ) : + trackContentObjectView( _pattern, _parent ), + m_pat( _pattern ), + m_paintPixmap(), + m_needsUpdate( TRUE ) +{ + if( s_stepBtnOn == NULL ) + { + s_stepBtnOn = new QPixmap( embed::getIconPixmap( + "step_btn_on_100" ) ); + } + + if( s_stepBtnOverlay == NULL ) + { + s_stepBtnOverlay = new QPixmap( embed::getIconPixmap( + "step_btn_on_yellow" ) ); + } + + if( s_stepBtnOff == NULL ) + { + s_stepBtnOff = new QPixmap( embed::getIconPixmap( + "step_btn_off" ) ); + } + + if( s_stepBtnOffLight == NULL ) + { + s_stepBtnOffLight = new QPixmap( embed::getIconPixmap( + "step_btn_off_light" ) ); + } + + if( s_frozen == NULL ) + { + s_frozen = new QPixmap( embed::getIconPixmap( "frozen" ) ); + } + + setFixedHeight( parentWidget()->height() - 2 ); + setAutoResizeEnabled( FALSE ); + + toolTip::add( this, + tr( "double-click to open this pattern in piano-roll\n" + "use mouse wheel to set volume of a step" ) ); +} + + + + + + +patternView::~patternView() +{ + if( engine::getPianoRoll()->currentPattern() == m_pat ) + { + engine::getPianoRoll()->setCurrentPattern( NULL ); + // we have to have the song-editor to stop playing if it played + // us before + if( engine::getSong()->playing() && + engine::getSong()->playMode() == + song::Mode_PlayPattern ) + { + engine::getSong()->playPattern( NULL ); + } + } +} + + + + + +void patternView::update( void ) +{ + m_needsUpdate = TRUE; + m_pat->changeLength( m_pat->length() ); + trackContentObjectView::update(); +} + + + + +void patternView::openInPianoRoll( void ) +{ + openInPianoRoll( FALSE ); +} + + + + +void patternView::openInPianoRoll( bool ) +{ + engine::getPianoRoll()->setCurrentPattern( m_pat ); + engine::getPianoRoll()->parentWidget()->show(); + engine::getPianoRoll()->setFocus(); +} + + + + +void patternView::resetName( void ) +{ + m_pat->setName( m_pat->m_instrumentTrack->name() ); +} + + + + +void patternView::changeName( void ) +{ + QString s = m_pat->name(); + renameDialog rename_dlg( s ); + rename_dlg.exec(); + m_pat->setName( s ); +} + + + + + +void patternView::addSteps( QAction * _item ) +{ + m_pat->addSteps( _item->text().toInt() ); +} + + + + +void patternView::removeSteps( QAction * _item ) +{ + m_pat->removeSteps( _item->text().toInt() ); +} + + + + +void patternView::constructContextMenu( QMenu * _cm ) +{ + QAction * a = new QAction( embed::getIconPixmap( "piano" ), + tr( "Open in piano-roll" ), _cm ); + _cm->insertAction( _cm->actions()[0], a ); + connect( a, SIGNAL( triggered( bool ) ), this, + SLOT( openInPianoRoll( bool ) ) ); + _cm->insertSeparator( _cm->actions()[1] ); + + _cm->addSeparator(); + + _cm->addAction( embed::getIconPixmap( "edit_erase" ), + tr( "Clear all notes" ), m_pat, SLOT( clear() ) ); + _cm->addSeparator(); + + _cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ), + this, SLOT( resetName() ) ); + _cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ), + this, SLOT( changeName() ) ); + _cm->addSeparator(); + + bool freeze_separator = FALSE; + if( !( m_pat->m_instrumentTrack->muted() || m_pat->muted() ) ) + { + _cm->addAction( embed::getIconPixmap( "freeze" ), + m_pat->m_frozenPattern ? tr( "Refreeze" ) : + tr( "Freeze" ), + m_pat, SLOT( freeze() ) ); + freeze_separator = TRUE; + } + if( m_pat->m_frozenPattern ) + { + _cm->addAction( embed::getIconPixmap( "unfreeze" ), + tr( "Unfreeze" ), m_pat, SLOT( unfreeze() ) ); + freeze_separator = TRUE; + } + if( freeze_separator ) + { + _cm->addSeparator(); + } + + QMenu * add_step_menu = _cm->addMenu( + embed::getIconPixmap( "step_btn_add" ), + tr( "Add steps" ) ); + QMenu * remove_step_menu = _cm->addMenu( + embed::getIconPixmap( "step_btn_remove" ), + tr( "Remove steps" ) ); + connect( add_step_menu, SIGNAL( triggered( QAction * ) ), + this, SLOT( addSteps( QAction * ) ) ); + connect( remove_step_menu, SIGNAL( triggered( QAction * ) ), + this, SLOT( removeSteps( QAction * ) ) ); + for( int i = 1; i <= 16; i *= 2 ) + { + const QString label = ( i == 1 ) ? + tr( "1 step" ) : + tr( "%1 steps" ).arg( i ); + add_step_menu->addAction( label ); + remove_step_menu->addAction( label ); + } +} + + + + +void patternView::mouseDoubleClickEvent( QMouseEvent * _me ) +{ + if( _me->button() != Qt::LeftButton ) + { + _me->ignore(); + return; + } + if( m_pat->type() == pattern::MelodyPattern || + !( m_pat->type() == pattern::BeatPattern && + ( pixelsPerTact() >= 192 || + m_pat->m_steps != DEFAULT_STEPS_PER_TACT ) && + _me->y() > height() - s_stepBtnOff->height() ) ) + { + openInPianoRoll(); + } +} + + + + +void patternView::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton && + m_pat->m_patternType == pattern::BeatPattern && + ( fixedTCOs() || pixelsPerTact() >= 192 || + m_pat->m_steps != DEFAULT_STEPS_PER_TACT ) && + _me->y() > height() - s_stepBtnOff->height() ) + { + int step = ( _me->x() - TCO_BORDER_WIDTH ) * + m_pat->length() / BEATS_PER_TACT / width(); + if( step >= m_pat->m_steps ) + { + return; + } + note * n = m_pat->m_notes[step]; + if( n->length() < 0 ) + { + n->setLength( 0 ); + } + else + { + n->setLength( -64 ); + } + engine::getSong()->setModified(); + update(); + if( engine::getPianoRoll()->currentPattern() == m_pat ) + { + engine::getPianoRoll()->update(); + } + } + else if( m_pat->m_frozenPattern != NULL && + _me->button() == Qt::LeftButton && + engine::getMainWindow()->isShiftPressed() == TRUE ) + { + QString s; + new stringPairDrag( "sampledata", + m_pat->m_frozenPattern->toBase64( s ), + embed::getIconPixmap( "freeze" ), + this ); + } + else + { + trackContentObjectView::mousePressEvent( _me ); + } +} + + + + +void patternView::wheelEvent( QWheelEvent * _we ) +{ + if( m_pat->m_patternType == pattern::BeatPattern && + ( fixedTCOs() || pixelsPerTact() >= 192 || + m_pat->m_steps != DEFAULT_STEPS_PER_TACT ) && + _we->y() > height() - s_stepBtnOff->height() ) + { + int step = ( _we->x() - TCO_BORDER_WIDTH ) * + m_pat->length() / BEATS_PER_TACT / width(); + if( step >= m_pat->m_steps ) + { + return; + } + note * n = m_pat->m_notes[step]; + Uint8 vol = n->getVolume(); + + if( n->length() == 0 && _we->delta() > 0 ) + { + n->setLength( -64 ); + n->setVolume( 5 ); + } + else if( _we->delta() > 0 ) + { + if( vol < 95 ) + { + n->setVolume( vol + 5 ); + } + } + else + { + if( vol > 5 ) + { + n->setVolume( vol - 5 ); + } + else + { + n->setLength( 0 ); + } + } + engine::getSong()->setModified(); + update(); + if( engine::getPianoRoll()->currentPattern() == m_pat ) + { + engine::getPianoRoll()->update(); + } + _we->accept(); + } + else + { + trackContentObjectView::wheelEvent( _we ); + } +} + + + + +void patternView::paintEvent( QPaintEvent * ) +{ + if( m_needsUpdate == FALSE ) + { + QPainter p( this ); + p.drawPixmap( 0, 0, m_paintPixmap ); + return; + } + + m_pat->changeLength( m_pat->length() ); + + m_needsUpdate = FALSE; + + if( m_paintPixmap.isNull() == TRUE || m_paintPixmap.size() != size() ) + { + m_paintPixmap = QPixmap( size() ); + } + + QPainter p( &m_paintPixmap ); + + QLinearGradient lingrad( 0, 0, 0, height() ); + const QColor c = isSelected() ? QColor( 0, 0, 224 ) : + QColor( 96, 96, 96 ); + lingrad.setColorAt( 0, c ); + lingrad.setColorAt( 0.5, Qt::black ); + lingrad.setColorAt( 1, c ); + p.fillRect( QRect( 1, 1, width() - 2, height() - 2 ), lingrad ); + + p.setPen( QColor( 57, 69, 74 ) ); + p.drawLine( 0, 0, width(), 0 ); + p.drawLine( 0, 0, 0, height() ); + p.setPen( QColor( 120, 130, 140 ) ); + p.drawLine( 0, height() - 1, width() - 1, height() - 1 ); + p.drawLine( width() - 1, 0, width() - 1, height() - 1 ); + + p.setPen( QColor( 0, 0, 0 ) ); + p.drawRect( 1, 1, width() - 2, height() - 2 ); + + const float ppt = fixedTCOs() ? + ( parentWidget()->width() - 2 * TCO_BORDER_WIDTH ) + / (float) m_pat->length().getTact() : + pixelsPerTact(); + + if( m_pat->m_patternType == pattern::MelodyPattern ) + { + Sint32 central_key = 0; + if( m_pat->m_notes.size() > 0 ) + { + // first determine the central tone so that we can + // display the area where most of the m_notes are + Sint32 total_notes = 0; + for( noteVector::iterator it = m_pat->m_notes.begin(); + it != m_pat->m_notes.end(); ++it ) + { + if( ( *it )->length() > 0 ) + { + central_key += ( *it )->key(); + ++total_notes; + } + } + + if( total_notes > 0 ) + { + central_key = central_key / total_notes; + + Sint16 central_y = height() / 2; + Sint16 y_base = central_y + TCO_BORDER_WIDTH -1; + + const Sint16 x_base = TCO_BORDER_WIDTH; + + p.setPen( QColor( 0, 0, 0 ) ); + for( tact tact_num = 1; tact_num < + m_pat->length().getTact(); ++tact_num ) + { + p.drawLine( + x_base + static_cast( + ppt * tact_num ) - 1, + TCO_BORDER_WIDTH, + x_base + static_cast( + ppt * tact_num ) - 1, + height() - 2 * + TCO_BORDER_WIDTH ); + } + if( m_pat->getTrack()->muted() || + m_pat->muted() ) + { + p.setPen( QColor( 160, 160, 160 ) ); + } + else if( m_pat->m_frozenPattern != NULL ) + { + p.setPen( QColor( 0x00, 0xE0, 0xFF ) ); + } + else + { + p.setPen( QColor( 0xFF, 0xB0, 0x00 ) ); + } + + for( noteVector::iterator it = + m_pat->m_notes.begin(); + it != m_pat->m_notes.end(); ++it ) + { + Sint8 y_pos = central_key - + ( *it )->key(); + + if( ( *it )->length() > 0 && + y_pos > -central_y && + y_pos < central_y ) + { + Sint16 x1 = 2 * x_base + + static_cast( ( *it )->pos() * ppt / 64 ); + Sint16 x2 = x1 + + static_cast( ( *it )->length() * ppt / 64 ); + p.drawLine( x1, y_base + y_pos, + x2, y_base + y_pos ); + + } + } + } + } + } + else if( m_pat->m_patternType == pattern::BeatPattern && + ( fixedTCOs() || ppt >= 96 + || m_pat->m_steps != DEFAULT_STEPS_PER_TACT ) ) + { + QPixmap stepon; + QPixmap stepoverlay; + QPixmap stepoff; + QPixmap stepoffl; + const int steps = m_pat->length() / BEATS_PER_TACT; + const int w = width() - 2 * TCO_BORDER_WIDTH; + stepon = s_stepBtnOn->scaled( w / steps, + s_stepBtnOn->height(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation ); + stepoverlay = s_stepBtnOverlay->scaled( w / steps, + s_stepBtnOn->height(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation ); + stepoff = s_stepBtnOff->scaled( w / steps, + s_stepBtnOff->height(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation ); + stepoffl = s_stepBtnOffLight->scaled( w / steps, + s_stepBtnOffLight->height(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation ); + for( noteVector::iterator it = m_pat->m_notes.begin(); + it != m_pat->m_notes.end(); ++it ) + { + Sint16 no = ( *it )->pos() / 4; + Sint16 x = TCO_BORDER_WIDTH + static_cast( no * + w / steps ); + Sint16 y = height() - s_stepBtnOff->height() - 1; + + Uint8 vol = ( *it )->getVolume(); + + if( ( *it )->length() < 0 ) + { + p.drawPixmap( x, y, stepoff ); + for( int i = 0; i < vol / 5 + 1; ++i ) + { + p.drawPixmap( x, y, stepon ); + } + for( int i = 0; i < ( 25 + ( vol - 75 ) ) / 5; + ++i ) + { + p.drawPixmap( x, y, stepoverlay ); + } + } + else if( ( no / BEATS_PER_TACT ) % 2 ) + { + p.drawPixmap( x, y, stepoff ); + } + else + { + p.drawPixmap( x, y, stepoffl ); + } + } + } + + p.setFont( pointSize<7>( p.font() ) ); + if( m_pat->muted() || m_pat->getTrack()->muted() ) + { + p.setPen( QColor( 192, 192, 192 ) ); + } + else + { + p.setPen( QColor( 32, 240, 32 ) ); + } + p.drawText( 2, p.fontMetrics().height() - 1, m_pat->name() ); + if( m_pat->muted() ) + { + p.drawPixmap( 3, p.fontMetrics().height() + 1, + embed::getIconPixmap( "muted", 16, 16 ) ); + } + else if( m_pat->m_frozenPattern != NULL ) + { + p.setPen( QColor( 0, 224, 255 ) ); + p.drawRect( 0, 0, width(), height() - 1 ); + p.drawPixmap( 3, height() - s_frozen->height() - 4, *s_frozen ); + } + + p.end(); + + p.begin( this ); + p.drawPixmap( 0, 0, m_paintPixmap ); + +} + + + + #include "pattern.moc" diff --git a/src/tracks/sample_track.cpp b/src/tracks/sample_track.cpp index b87373639c..0b07441aae 100644 --- a/src/tracks/sample_track.cpp +++ b/src/tracks/sample_track.cpp @@ -329,7 +329,7 @@ void sampleTCOSettingsDialog::setSampleFile( const QString & _f ) sampleTrack::sampleTrack( trackContainer * _tc ) : - track( _tc ), + track( SampleTrack, _tc ), m_audioPort( tr( "Sample track" ), this ), m_volumeModel( DEFAULT_VOLUME, MIN_VOLUME, MAX_VOLUME, 1/*, this*/ ) { @@ -377,14 +377,6 @@ sampleTrack::~sampleTrack() -track::trackTypes sampleTrack::type( void ) const -{ - return( SAMPLE_TRACK ); -} - - - - bool FASTCALL sampleTrack::play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _offset, diff --git a/src/widgets/automatable_button.cpp b/src/widgets/automatable_button.cpp index d7846e43a2..2a127e1a63 100644 --- a/src/widgets/automatable_button.cpp +++ b/src/widgets/automatable_button.cpp @@ -176,9 +176,10 @@ automatableButtonGroup::automatableButtonGroup( QWidget * _parent, automatableButtonGroup::~automatableButtonGroup() { - while( m_buttons.empty() == FALSE ) + for( QList::iterator it = m_buttons.begin(); + it != m_buttons.end(); ++it ) { - removeButton( m_buttons.front() ); + ( *it )->m_group = NULL; } } diff --git a/src/widgets/effect_rack_view.cpp b/src/widgets/effect_rack_view.cpp index a10ceddb7f..392493863c 100644 --- a/src/widgets/effect_rack_view.cpp +++ b/src/widgets/effect_rack_view.cpp @@ -43,7 +43,7 @@ effectRackView::effectRackView( effectChain * _model, QWidget * _parent ) : modelView( NULL ) { setFixedSize( 230, 184 ); - + /* m_mainLayout = new QVBoxLayout( this ); m_mainLayout->setMargin( 0 ); m_mainLayout->setSpacing( 0 );*/ diff --git a/src/widgets/envelope_and_lfo_view.cpp b/src/widgets/envelope_and_lfo_view.cpp new file mode 100644 index 0000000000..f5db2d292d --- /dev/null +++ b/src/widgets/envelope_and_lfo_view.cpp @@ -0,0 +1,600 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * envelope_and_lfo_view.cpp - widget which is m_used by envelope/lfo/filter- + * tab of channel-window + * + * Copyright (c) 2004-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 "envelope_and_lfo_view.h" + + +#include +#include + + +#include "envelope_and_lfo_parameters.h" +#include "embed.h" +#include "engine.h" +#include "gui_templates.h" +#include "knob.h" +#include "led_checkbox.h" +#include "mmp.h" +#include "oscillator.h" +#include "pixmap_button.h" +#include "string_pair_drag.h" +#include "tempo_sync_knob.h" +#include "text_float.h" +#include "tooltip.h" +#include "track.h" +#include "automatable_model_templates.h" + + + +// how long should be each envelope-segment maximal (e.g. attack)? +const float SECS_PER_ENV_SEGMENT = 5.0f; +// how long should be one LFO-oscillation maximal? +const float SECS_PER_LFO_OSCILLATION = 20.0f; + + +const int ENV_GRAPH_X = 6; +const int ENV_GRAPH_Y = 6; + +const int ENV_KNOBS_Y = 43; +const int ENV_KNOBS_LBL_Y = ENV_KNOBS_Y+35; +const int KNOB_X_SPACING = 32; +const int PREDELAY_KNOB_X = 6; +const int ATTACK_KNOB_X = PREDELAY_KNOB_X+KNOB_X_SPACING; +const int HOLD_KNOB_X = ATTACK_KNOB_X+KNOB_X_SPACING; +const int DECAY_KNOB_X = HOLD_KNOB_X+KNOB_X_SPACING; +const int SUSTAIN_KNOB_X = DECAY_KNOB_X+KNOB_X_SPACING; +const int RELEASE_KNOB_X = SUSTAIN_KNOB_X+KNOB_X_SPACING; +const int AMOUNT_KNOB_X = RELEASE_KNOB_X+KNOB_X_SPACING; + +const float TIME_UNIT_WIDTH = 36.0; + + +const int LFO_GRAPH_X = 6; +const int LFO_GRAPH_Y = ENV_KNOBS_LBL_Y+14; +const int LFO_KNOB_Y = LFO_GRAPH_Y-2; +const int LFO_PREDELAY_KNOB_X = LFO_GRAPH_X + 100; +const int LFO_ATTACK_KNOB_X = LFO_PREDELAY_KNOB_X+KNOB_X_SPACING; +const int LFO_SPEED_KNOB_X = LFO_ATTACK_KNOB_X+KNOB_X_SPACING; +const int LFO_AMOUNT_KNOB_X = LFO_SPEED_KNOB_X+KNOB_X_SPACING; +const int LFO_SHAPES_X = LFO_GRAPH_X;//PREDELAY_KNOB_X; +const int LFO_SHAPES_Y = LFO_GRAPH_Y + 50; + + +QPixmap * envelopeAndLFOView::s_envGraph = NULL; +QPixmap * envelopeAndLFOView::s_lfoGraph = NULL; + + + +envelopeAndLFOView::envelopeAndLFOView( QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_params( NULL ) +{ + if( s_envGraph == NULL ) + { + s_envGraph = new QPixmap( embed::getIconPixmap( + "envelope_graph" ) ); + } + if( s_lfoGraph == NULL ) + { + s_lfoGraph = new QPixmap( embed::getIconPixmap( "lfo_graph" ) ); + } + + m_predelayKnob = new knob( knobBright_26, this, tr( "Predelay-time" ) ); + m_predelayKnob->setLabel( tr( "DEL" ) ); + m_predelayKnob->move( PREDELAY_KNOB_X, ENV_KNOBS_Y ); + m_predelayKnob->setHintText( tr( "Predelay:" ) + " ", "" ); + m_predelayKnob->setWhatsThis( + tr( "Use this knob for setting predelay of the current " + "envelope. The bigger this value the longer the time " + "before start of actual envelope." ) ); + + + m_attackKnob = new knob( knobBright_26, this, tr( "Attack-time" ) ); + m_attackKnob->setLabel( tr( "ATT" ) ); + m_attackKnob->move( ATTACK_KNOB_X, ENV_KNOBS_Y ); + m_attackKnob->setHintText( tr( "Attack:" )+" ", "" ); + m_attackKnob->setWhatsThis( + tr( "Use this knob for setting attack-time of the current " + "envelope. The bigger this value the longer the " + "envelope needs to increase to attack-level. " + "Choose a small value for instruments like pianos " + "and a big value for strings." ) ); + + m_holdKnob = new knob( knobBright_26, this, tr( "Hold-time" ) ); + m_holdKnob->setLabel( tr( "HOLD" ) ); + m_holdKnob->move( HOLD_KNOB_X, ENV_KNOBS_Y ); + m_holdKnob->setHintText( tr( "Hold:" ) + " ", "" ); + m_holdKnob->setWhatsThis( + tr( "Use this knob for setting hold-time of the current " + "envelope. The bigger this value the longer the " + "envelope holds attack-level before it begins to " + "decrease to sustain-level." ) ); + + m_decayKnob = new knob( knobBright_26, this, tr( "Decay-time" ) ); + m_decayKnob->setLabel( tr( "DEC" ) ); + m_decayKnob->move( DECAY_KNOB_X, ENV_KNOBS_Y ); + m_decayKnob->setHintText( tr( "Decay:" ) + " ", "" ); + m_decayKnob->setWhatsThis( + tr( "Use this knob for setting decay-time of the current " + "envelope. The bigger this value the longer the " + "envelope needs to decrease from attack-level to " + "sustain-level. Choose a small value for instruments " + "like pianos." ) ); + + + m_sustainKnob = new knob( knobBright_26, this, tr( "Sustain-level" ) ); + m_sustainKnob->setLabel( tr( "SUST" ) ); + m_sustainKnob->move( SUSTAIN_KNOB_X, ENV_KNOBS_Y ); + m_sustainKnob->setHintText( tr( "Sustain:" ) + " ", "" ); + m_sustainKnob->setWhatsThis( + tr( "Use this knob for setting sustain-level of the current " + "envelope. The bigger this value the higher the level " + "on which the envelope stays before going down to " + "zero." ) ); + + + m_releaseKnob = new knob( knobBright_26, this, tr( "Release-time" ) ); + m_releaseKnob->setLabel( tr( "REL" ) ); + m_releaseKnob->move( RELEASE_KNOB_X, ENV_KNOBS_Y ); + m_releaseKnob->setHintText( tr( "Release:" ) + " ", "" ); + m_releaseKnob->setWhatsThis( + tr( "Use this knob for setting release-time of the current " + "envelope. The bigger this value the longer the " + "envelope needs to decrease from sustain-level to " + "zero. Choose a big value for soft instruments like " + "strings." ) ); + + + m_amountKnob = new knob( knobBright_26, this, + tr( "Modulation amount" ) ); + m_amountKnob->setLabel( tr( "AMT" ) ); + m_amountKnob->move( AMOUNT_KNOB_X, ENV_GRAPH_Y ); + m_amountKnob->setHintText( tr( "Modulation amount:" ) + " ", "" ); + m_amountKnob->setWhatsThis( + tr( "Use this knob for setting modulation amount of the " + "current envelope. The bigger this value the more the " + "according size (e.g. volume or cutoff-frequency) " + "will be influenced by this envelope." ) ); + + + + + m_lfoPredelayKnob = new knob( knobBright_26, this, + tr( "LFO-predelay-time" ) ); + m_lfoPredelayKnob->setLabel( tr( "DEL" ) ); + m_lfoPredelayKnob->move( LFO_PREDELAY_KNOB_X, LFO_KNOB_Y ); + m_lfoPredelayKnob->setHintText( tr( "LFO-predelay:" ) + " ", "" ); + m_lfoPredelayKnob->setWhatsThis( + tr( "Use this knob for setting predelay-time of the current " + "LFO. The bigger this value the the time until the " + "LFO starts to oscillate." ) ); + + + m_lfoAttackKnob = new knob( knobBright_26, this, + tr( "LFO-attack-time" ) ); + m_lfoAttackKnob->setLabel( tr( "ATT" ) ); + m_lfoAttackKnob->move( LFO_ATTACK_KNOB_X, LFO_KNOB_Y ); + m_lfoAttackKnob->setHintText( tr( "LFO-attack:" ) + " ", "" ); + m_lfoAttackKnob->setWhatsThis( + tr( "Use this knob for setting attack-time of the current LFO. " + "The bigger this value the longer the LFO needs to " + "increase its amplitude to maximum." ) ); + + + m_lfoSpeedKnob = new tempoSyncKnob( knobBright_26, this, + tr( "LFO-speed" ), 20000.0 ); + m_lfoSpeedKnob->setLabel( tr( "SPD" ) ); + m_lfoSpeedKnob->move( LFO_SPEED_KNOB_X, LFO_KNOB_Y ); + m_lfoSpeedKnob->setHintText( tr( "LFO-speed:" ) + " ", "" ); + m_lfoSpeedKnob->setWhatsThis( + tr( "Use this knob for setting speed of the current LFO. The " + "bigger this value the faster the LFO oscillates and " + "the faster will be your effect." ) ); + + + m_lfoAmountKnob = new knob( knobBright_26, this, + tr( "LFO-modulation-amount" ) ); + m_lfoAmountKnob->setLabel( tr( "AMT" ) ); + m_lfoAmountKnob->move( LFO_AMOUNT_KNOB_X, LFO_KNOB_Y ); + m_lfoAmountKnob->setHintText( tr( "Modulation amount:" ) + " ", "" ); + m_lfoAmountKnob->setWhatsThis( + tr( "Use this knob for setting modulation amount of the " + "current LFO. The bigger this value the more the " + "selected size (e.g. volume or cutoff-frequency) will " + "be influenced by this LFO." ) ); + + + pixmapButton * sin_lfo_btn = new pixmapButton( this, NULL ); + sin_lfo_btn->move( LFO_SHAPES_X, LFO_SHAPES_Y ); + sin_lfo_btn->setActiveGraphic( embed::getIconPixmap( + "sin_wave_active" ) ); + sin_lfo_btn->setInactiveGraphic( embed::getIconPixmap( + "sin_wave_inactive" ) ); + sin_lfo_btn->setWhatsThis( + tr( "Click here if you want a sine-wave for current " + "oscillator." ) ); + + pixmapButton * triangle_lfo_btn = new pixmapButton( this, NULL ); + triangle_lfo_btn->move( LFO_SHAPES_X+15, LFO_SHAPES_Y ); + triangle_lfo_btn->setActiveGraphic( embed::getIconPixmap( + "triangle_wave_active" ) ); + triangle_lfo_btn->setInactiveGraphic( embed::getIconPixmap( + "triangle_wave_inactive" ) ); + triangle_lfo_btn->setWhatsThis( + tr( "Click here if you want a triangle-wave for current " + "oscillator." ) ); + + pixmapButton * saw_lfo_btn = new pixmapButton( this, NULL ); + saw_lfo_btn->move( LFO_SHAPES_X+30, LFO_SHAPES_Y ); + saw_lfo_btn->setActiveGraphic( embed::getIconPixmap( + "saw_wave_active" ) ); + saw_lfo_btn->setInactiveGraphic( embed::getIconPixmap( + "saw_wave_inactive" ) ); + saw_lfo_btn->setWhatsThis( + tr( "Click here if you want a saw-wave for current " + "oscillator." ) ); + + pixmapButton * sqr_lfo_btn = new pixmapButton( this, NULL ); + sqr_lfo_btn->move( LFO_SHAPES_X+45, LFO_SHAPES_Y ); + sqr_lfo_btn->setActiveGraphic( embed::getIconPixmap( + "square_wave_active" ) ); + sqr_lfo_btn->setInactiveGraphic( embed::getIconPixmap( + "square_wave_inactive" ) ); + sqr_lfo_btn->setWhatsThis( + tr( "Click here if you want a square-wave for current " + "oscillator." ) ); + + m_userLfoBtn = new pixmapButton( this, NULL ); + m_userLfoBtn->move( LFO_SHAPES_X+60, LFO_SHAPES_Y ); + m_userLfoBtn->setActiveGraphic( embed::getIconPixmap( + "usr_wave_active" ) ); + m_userLfoBtn->setInactiveGraphic( embed::getIconPixmap( + "usr_wave_inactive" ) ); + m_userLfoBtn->setWhatsThis( + tr( "Click here if you want a user-defined wave for current " + "oscillator. Afterwards drag an according sample-" + "file into LFO-graph." ) ); + + connect( m_userLfoBtn, SIGNAL( toggled( bool ) ), + this, SLOT( lfoUserWaveChanged() ) ); + + m_lfoWaveBtnGrp = new automatableButtonGroup( this, + tr( "LFO wave shape" ) ); + m_lfoWaveBtnGrp->addButton( sin_lfo_btn ); + m_lfoWaveBtnGrp->addButton( triangle_lfo_btn ); + m_lfoWaveBtnGrp->addButton( saw_lfo_btn ); + m_lfoWaveBtnGrp->addButton( sqr_lfo_btn ); + m_lfoWaveBtnGrp->addButton( m_userLfoBtn ); + + + m_x100Cb = new ledCheckBox( tr( "FREQ x 100" ), this, + tr( "Freq x 100" ) ); + m_x100Cb->setFont( pointSize<6>( m_x100Cb->font() ) ); + m_x100Cb->move( LFO_PREDELAY_KNOB_X, LFO_GRAPH_Y + 36 ); + m_x100Cb->setWhatsThis( + tr( "Click here if the frequency of this LFO should be " + "multiplied with 100." ) ); + toolTip::add( m_x100Cb, tr( "multiply LFO-frequency with 100" ) ); + + + m_controlEnvAmountCb = new ledCheckBox( tr( "MODULATE ENV-AMOUNT" ), + this, tr( "Modulate Env-Amount" ) ); + m_controlEnvAmountCb->move( LFO_PREDELAY_KNOB_X, LFO_GRAPH_Y + 54 ); + m_controlEnvAmountCb->setFont( pointSize<6>( + m_controlEnvAmountCb->font() ) ); + m_controlEnvAmountCb ->setWhatsThis( + tr( "Click here to make the envelope-amount controlled by this " + "LFO." ) ); + toolTip::add( m_controlEnvAmountCb, + tr( "control envelope-amount by this LFO" ) ); + + + setAcceptDrops( TRUE ); + +} + + + + +envelopeAndLFOView::~envelopeAndLFOView() +{ + delete m_lfoWaveBtnGrp; +} + + + + +void envelopeAndLFOView::modelChanged( void ) +{ + m_params = castModel(); + m_predelayKnob->setModel( &m_params->m_predelayModel ); + m_attackKnob->setModel( &m_params->m_attackModel ); + m_holdKnob->setModel( &m_params->m_holdModel ); + m_decayKnob->setModel( &m_params->m_decayModel ); + m_sustainKnob->setModel( &m_params->m_sustainModel ); + m_releaseKnob->setModel( &m_params->m_releaseModel ); + m_amountKnob->setModel( &m_params->m_amountModel ); + m_lfoPredelayKnob->setModel( &m_params->m_lfoPredelayModel ); + m_lfoAttackKnob->setModel( &m_params->m_lfoAttackModel ); + m_lfoSpeedKnob->setModel( &m_params->m_lfoSpeedModel ); + m_lfoAmountKnob->setModel( &m_params->m_lfoAmountModel ); + m_lfoWaveBtnGrp->setModel( &m_params->m_lfoWaveModel ); + m_x100Cb->setModel( &m_params->m_x100Model ); + m_controlEnvAmountCb->setModel( &m_params->m_controlEnvAmountModel ); +} + + + + +void envelopeAndLFOView::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() != Qt::LeftButton ) + { + return; + } + + if( QRect( ENV_GRAPH_X, ENV_GRAPH_Y, s_envGraph->width(), + s_envGraph->height() ).contains( _me->pos() ) == TRUE ) + { + if( m_amountKnob->value() < 1.0f ) + { + m_amountKnob->setValue( 1.0f ); + } + else + { + m_amountKnob->setValue( 0.0f ); + } + } + else if( QRect( LFO_GRAPH_X, LFO_GRAPH_Y, s_lfoGraph->width(), + s_lfoGraph->height() ).contains( _me->pos() ) == TRUE ) + { + if( m_lfoAmountKnob->value() < 1.0f ) + { + m_lfoAmountKnob->setValue( 1.0f ); + } + else + { + m_lfoAmountKnob->setValue( 0.0f ); + } + } +} + + + + +void envelopeAndLFOView::dragEnterEvent( QDragEnterEvent * _dee ) +{ + stringPairDrag::processDragEnterEvent( _dee, + QString( "samplefile,tco_%1" ).arg( + track::SampleTrack ) ); +} + + + + +void envelopeAndLFOView::dropEvent( QDropEvent * _de ) +{ + QString type = stringPairDrag::decodeKey( _de ); + QString value = stringPairDrag::decodeValue( _de ); + if( type == "samplefile" ) + { + m_params->m_userWave.setAudioFile( + stringPairDrag::decodeValue( _de ) ); + m_userLfoBtn->model()->setValue( TRUE ); + _de->accept(); + } + else if( type == QString( "tco_%1" ).arg( track::SampleTrack ) ) + { + multimediaProject mmp( value, FALSE ); + m_params->m_userWave.setAudioFile( + mmp.content().firstChild().toElement(). + attribute( "src" ) ); + m_userLfoBtn->model()->setValue( TRUE ); + _de->accept(); + } +} + + + + +void envelopeAndLFOView::paintEvent( QPaintEvent * ) +{ + QPainter p( this ); + p.setRenderHint( QPainter::Antialiasing ); + + // set smaller font + p.setFont( pointSize<6>( p.font() ) ); + + // draw envelope-graph + p.drawPixmap( ENV_GRAPH_X, ENV_GRAPH_Y, *s_envGraph ); + // draw LFO-graph + p.drawPixmap( LFO_GRAPH_X, LFO_GRAPH_Y, *s_lfoGraph ); + + + p.setFont( pointSize<8>( p.font() ) ); + + const float gray_amount = 1.0f - fabsf( m_amountKnob->value() ); + + p.setPen( QPen( QColor( static_cast( 96 * gray_amount ), + static_cast( 255 - 159 * gray_amount ), + static_cast( 128 - 32 * gray_amount ) ), + 2 ) ); + + const QColor end_points_color( 0xFF, 0xBF, 0x22 ); + const QColor end_points_bg_color( 0, 0, 2 ); + + const int y_base = ENV_GRAPH_Y + s_envGraph->height() - 3; + const int avail_height = s_envGraph->height() - 6; + + int x1 = ENV_GRAPH_X + 2 + static_cast( m_predelayKnob->value() * + TIME_UNIT_WIDTH ); + int x2 = x1 + static_cast( m_attackKnob->value() * + TIME_UNIT_WIDTH ); + + p.drawLine( x1, y_base, x2, y_base - avail_height ); + p.fillRect( x1 - 1, y_base - 2, 4, 4, end_points_bg_color ); + p.fillRect( x1, y_base - 1, 2, 2, end_points_color ); + x1 = x2; + x2 = x1 + static_cast( m_holdKnob->value() * TIME_UNIT_WIDTH ); + + p.drawLine( x1, y_base - avail_height, x2, y_base - avail_height ); + p.fillRect( x1 - 1, y_base - 2 - avail_height, 4, 4, + end_points_bg_color ); + p.fillRect( x1, y_base-1-avail_height, 2, 2, end_points_color ); + x1 = x2; + x2 = x1 + static_cast( ( m_decayKnob->value() * + m_sustainKnob->value() ) * + TIME_UNIT_WIDTH ); + + p.drawLine( x1, y_base-avail_height, x2, static_cast( y_base - + avail_height + + m_sustainKnob->value() * avail_height ) ); + p.fillRect( x1 - 1, y_base - 2 - avail_height, 4, 4, + end_points_bg_color ); + p.fillRect( x1, y_base - 1 - avail_height, 2, 2, end_points_color ); + x1 = x2; + x2 = x1 + static_cast( m_releaseKnob->value() * TIME_UNIT_WIDTH ); + + p.drawLine( x1, static_cast( y_base - avail_height + + m_sustainKnob->value() * + avail_height ), x2, y_base ); + p.fillRect( x1-1, static_cast( y_base - avail_height + + m_sustainKnob->value() * + avail_height ) - 2, 4, 4, + end_points_bg_color ); + p.fillRect( x1, static_cast( y_base - avail_height + + m_sustainKnob->value() * + avail_height ) - 1, 2, 2, + end_points_color ); + p.fillRect( x2 - 1, y_base - 2, 4, 4, end_points_bg_color ); + p.fillRect( x2, y_base - 1, 2, 2, end_points_color ); + + + int LFO_GRAPH_W = s_lfoGraph->width() - 6; // substract border + int LFO_GRAPH_H = s_lfoGraph->height() - 6; // substract border + int graph_x_base = LFO_GRAPH_X + 3; + int graph_y_base = LFO_GRAPH_Y + 3 + LFO_GRAPH_H / 2; + + const float frames_for_graph = SECS_PER_LFO_OSCILLATION * + engine::getMixer()->sampleRate() / 10; + + const float lfo_gray_amount = 1.0f - fabsf( m_lfoAmountKnob->value() ); + p.setPen( QPen( QColor( static_cast( 96 * lfo_gray_amount ), + static_cast( 255 - 159 * lfo_gray_amount ), + static_cast( 128 - 32 * + lfo_gray_amount ) ), + 1.5 ) ); + + + float osc_frames = m_params->m_lfoOscillationFrames; + + if( m_params->m_x100Model.value() ) + { + osc_frames *= 100.0f; + } + + float old_y = 0; + for( int x = 0; x <= LFO_GRAPH_W; ++x ) + { + float val = 0.0; + float cur_sample = x * frames_for_graph / LFO_GRAPH_W; + if( static_cast( cur_sample ) > + m_params->m_lfoPredelayFrames ) + { + float phase = ( cur_sample -= + m_params->m_lfoPredelayFrames ) / + osc_frames; + switch( m_params->m_lfoWaveModel.value() ) + { + case envelopeAndLFOParameters::SineWave: + val = oscillator::sinSample( phase ); + break; + case envelopeAndLFOParameters::TriangleWave: + val = oscillator::triangleSample( + phase ); + break; + case envelopeAndLFOParameters::SawWave: + val = oscillator::sawSample( phase ); + break; + case envelopeAndLFOParameters::SquareWave: + val = oscillator::squareSample( phase ); + break; + case envelopeAndLFOParameters::UserDefinedWave: + val = m_params->m_userWave. + userWaveSample( phase ); + } + if( static_cast( cur_sample ) <= + m_params->m_lfoAttackFrames ) + { + val *= cur_sample / m_params->m_lfoAttackFrames; + } + } + float cur_y = -LFO_GRAPH_H / 2.0f * val; + p.drawLine( QLineF( graph_x_base + x - 1, graph_y_base + old_y, + graph_x_base + x, + graph_y_base + cur_y ) ); + old_y = cur_y; + } + + p.setPen( QColor( 255, 192, 0 ) ); + int ms_per_osc = static_cast( SECS_PER_LFO_OSCILLATION * + m_lfoSpeedKnob->value() * + 1000.0f ); + p.drawText( LFO_GRAPH_X + 4, LFO_GRAPH_Y + s_lfoGraph->height() - 6, + tr( "ms/LFO:" ) ); + p.drawText( LFO_GRAPH_X + 52, LFO_GRAPH_Y + s_lfoGraph->height() - 6, + QString::number( ms_per_osc ) ); + +} + + + + +void envelopeAndLFOView::lfoUserWaveChanged( void ) +{ + if( m_params->m_lfoWaveModel.value() == + envelopeAndLFOParameters::UserDefinedWave ) + { + if( m_params->m_userWave.frames() <= 1 ) + { + textFloat::displayMessage( tr( "Hint" ), + tr( "Drag a sample from somewhere and drop " + "it in this window." ), + embed::getIconPixmap( "hint" ), 3000 ); + } + } +} + + + + +#include "envelope_and_lfo_view.moc" + + +#endif diff --git a/src/widgets/instrument_function_views.cpp b/src/widgets/instrument_function_views.cpp new file mode 100644 index 0000000000..0a025746ab --- /dev/null +++ b/src/widgets/instrument_function_views.cpp @@ -0,0 +1,254 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * instrument_function_views.cpp - view for instrument-functions-tab + * + * Copyright (c) 2004-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include + +#include "instrument_functions.h" +#include "instrument_function_views.h" +#include "combobox.h" +#include "embed.h" +#include "engine.h" +#include "group_box.h" +#include "gui_templates.h" +#include "knob.h" +#include "led_checkbox.h" +#include "pixmap_button.h" +#include "tempo_sync_knob.h" +#include "tooltip.h" + + + +const int CHORDS_GROUPBOX_X = 4; +const int CHORDS_GROUPBOX_Y = 5; +const int CHORDS_GROUPBOX_WIDTH = 238; +const int CHORDS_GROUPBOX_HEIGHT = 65; +const int ARP_GROUPBOX_X = CHORDS_GROUPBOX_X; +const int ARP_GROUPBOX_Y = 10 + CHORDS_GROUPBOX_Y + CHORDS_GROUPBOX_HEIGHT; +const int ARP_GROUPBOX_WIDTH = CHORDS_GROUPBOX_WIDTH; +const int ARP_GROUPBOX_HEIGHT = 240 - ARP_GROUPBOX_Y; + + + +chordCreatorView::chordCreatorView( chordCreator * _cc, QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_cc( _cc ), + m_chordsGroupBox( new groupBox( tr( "CHORDS" ), this ) ), + m_chordsComboBox( new comboBox( m_chordsGroupBox, + tr( "Chord type" ) ) ), + m_chordRangeKnob( new knob( knobBright_26, m_chordsGroupBox, + tr( "Chord range" ) ) ) +{ + move( CHORDS_GROUPBOX_X, CHORDS_GROUPBOX_Y ); + setFixedSize( 250, CHORDS_GROUPBOX_HEIGHT ); + m_chordsGroupBox->setGeometry( 0, 0, CHORDS_GROUPBOX_WIDTH, + CHORDS_GROUPBOX_HEIGHT ); + + + m_chordsComboBox->setGeometry( 10, 25, 140, 22 ); + + + m_chordRangeKnob->setLabel( tr( "RANGE" ) ); + m_chordRangeKnob->move( 164, 24 ); + m_chordRangeKnob->setHintText( tr( "Chord range:" ) + " ", " " + + tr( "octave(s)" ) ); + m_chordRangeKnob->setWhatsThis( + tr( "Use this knob for setting the chord range in octaves. " + "The selected chord will be played within specified " + "amount of octaves." ) ); + +} + + + + +chordCreatorView::~chordCreatorView() +{ +} + + + + +void chordCreatorView::modelChanged( void ) +{ + m_cc = castModel(); + m_chordsGroupBox->setModel( &m_cc->m_chordsEnabledModel ); + m_chordsComboBox->setModel( &m_cc->m_chordsModel ); + m_chordRangeKnob->setModel( &m_cc->m_chordRangeModel ); +} + + + + + + + +arpeggiatorView::arpeggiatorView( arpeggiator * _arp, QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_a( _arp ), + m_arpGroupBox( new groupBox( tr( "ARPEGGIO" ), this ) ), + m_arpComboBox( new comboBox( m_arpGroupBox, tr( "Arpeggio type" ) ) ), + m_arpRangeKnob( new knob( knobBright_26, m_arpGroupBox, + tr( "Arpeggio range" ) ) ), + m_arpTimeKnob( new tempoSyncKnob( knobBright_26, m_arpGroupBox, + tr( "Arpeggio time" ) ) ), + m_arpGateKnob( new knob( knobBright_26, m_arpGroupBox, + tr( "Arpeggio gate" ) ) ), + m_arpModeComboBox( new comboBox( m_arpGroupBox, + tr( "Arpeggio mode" ) ) ) +{ + move( ARP_GROUPBOX_X, ARP_GROUPBOX_Y ); + setFixedSize( 250, ARP_GROUPBOX_HEIGHT ); + m_arpGroupBox->setGeometry( 0, 0, ARP_GROUPBOX_WIDTH, + ARP_GROUPBOX_HEIGHT ); + + m_arpGroupBox->setWhatsThis( + tr( "An arpeggio is a type of playing (especially plucked) " + "instruments, which makes the music much livelier. " + "The strings of such instruments (e.g. harps) are " + "plucked like chords, the only difference is, that " + "this is done in a sequential order, so the notes are " + "not played at the same time. Typical arpeggios are " + "major or minor triads. But there're a lot of other " + "possible chords, you can select." ) ); + + + m_arpComboBox->setGeometry( 10, 25, 140, 22 ); + + + m_arpRangeKnob->setLabel( tr( "RANGE" ) ); + m_arpRangeKnob->move( 164, 24 ); + m_arpRangeKnob->setHintText( tr( "Arpeggio range:" ) + " ", " " + + tr( "octave(s)" ) ); + m_arpRangeKnob->setWhatsThis( + tr( "Use this knob for setting the arpeggio range in octaves. " + "The selected arpeggio will be played within specified " + "amount of octaves." ) ); + + + m_arpTimeKnob->setLabel( tr( "TIME" ) ); + m_arpTimeKnob->move( 164, 70 ); + m_arpTimeKnob->setHintText( tr( "Arpeggio time:" ) + " ", " " + + tr( "ms" ) ); + m_arpTimeKnob->setWhatsThis( + tr( "Use this knob for setting the arpeggio time in " + "milliseconds. The arpeggio time specifies how long " + "each arpeggio-tone should be played." ) ); + + + m_arpGateKnob->setLabel( tr( "GATE" ) ); + m_arpGateKnob->move( 204, 70 ); + m_arpGateKnob->setHintText( tr( "Arpeggio gate:" ) + " ", tr( "%" ) ); + m_arpGateKnob->setWhatsThis( + tr( "Use this knob for setting the arpeggio gate. The " + "arpeggio gate specifies the percent of a whole " + "arpeggio-tone that should be played. With this you " + "can make cool staccato-arpeggios." ) ); + + m_arpDirectionLbl = new QLabel( tr( "Direction:" ), m_arpGroupBox ); + m_arpDirectionLbl->setGeometry( 10, 60, 64, 10 ); + m_arpDirectionLbl->setFont( pointSize<7>( m_arpDirectionLbl->font() ) ); + + + + pixmapButton * arp_up_btn = new pixmapButton( m_arpGroupBox, NULL ); + arp_up_btn->move( 10, 74 ); + arp_up_btn->setActiveGraphic( embed::getIconPixmap( "arp_up_on" ) ); + arp_up_btn->setInactiveGraphic( embed::getIconPixmap( "arp_up_off" ) ); + toolTip::add( arp_up_btn, tr( "arpeggio direction = up" ) ); + + + pixmapButton * arp_down_btn = new pixmapButton( m_arpGroupBox, NULL ); + arp_down_btn->move( 30, 74 ); + arp_down_btn->setActiveGraphic( embed::getIconPixmap( "arp_down_on" ) ); + arp_down_btn->setInactiveGraphic( embed::getIconPixmap( + "arp_down_off" ) ); + toolTip::add( arp_down_btn, tr( "arpeggio direction = down" ) ); + + + pixmapButton * arp_up_and_down_btn = new pixmapButton( m_arpGroupBox, + NULL ); + arp_up_and_down_btn->move( 50, 74 ); + arp_up_and_down_btn->setActiveGraphic( embed::getIconPixmap( + "arp_up_and_down_on" ) ); + arp_up_and_down_btn->setInactiveGraphic( embed::getIconPixmap( + "arp_up_and_down_off" ) ); + toolTip::add( arp_up_and_down_btn, + tr( "arpeggio direction = up and down" ) ); + + + pixmapButton * arp_random_btn = new pixmapButton( m_arpGroupBox, NULL ); + arp_random_btn->move( 70, 74 ); + arp_random_btn->setActiveGraphic( embed::getIconPixmap( + "arp_random_on" ) ); + arp_random_btn->setInactiveGraphic( embed::getIconPixmap( + "arp_random_off" ) ); + toolTip::add( arp_random_btn, tr( "arpeggio direction = random" ) ); + + m_arpDirectionBtnGrp = new automatableButtonGroup( this, + tr( "Arpeggio direction" ) ); + m_arpDirectionBtnGrp->addButton( arp_up_btn ); + m_arpDirectionBtnGrp->addButton( arp_down_btn ); + m_arpDirectionBtnGrp->addButton( arp_up_and_down_btn ); + m_arpDirectionBtnGrp->addButton( arp_random_btn ); + + + + QLabel * mode_lbl = new QLabel( tr( "Mode:" ), m_arpGroupBox ); + mode_lbl->setGeometry( 10, 104, 64, 10 ); + mode_lbl->setFont( pointSize<7>( mode_lbl->font() ) ); + + m_arpModeComboBox->setGeometry( 10, 118, 128, 22 ); +} + + + + +arpeggiatorView::~arpeggiatorView() +{ +} + + + + +void arpeggiatorView::modelChanged( void ) +{ + m_a = castModel(); + m_arpGroupBox->setModel( &m_a->m_arpEnabledModel ); + m_arpComboBox->setModel( &m_a->m_arpModel ); + m_arpRangeKnob->setModel( &m_a->m_arpRangeModel ); + m_arpTimeKnob->setModel( &m_a->m_arpTimeModel ); + m_arpGateKnob->setModel( &m_a->m_arpGateModel ); + m_arpDirectionBtnGrp->setModel( &m_a->m_arpDirectionModel ); + m_arpModeComboBox->setModel( &m_a->m_arpModeModel ); +} + + + + +#endif diff --git a/src/widgets/instrument_midi_io_view.cpp b/src/widgets/instrument_midi_io_view.cpp new file mode 100644 index 0000000000..91db2d30c5 --- /dev/null +++ b/src/widgets/instrument_midi_io_view.cpp @@ -0,0 +1,207 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * instrument_midi_io_view.cpp - MIDI-IO-View + * + * Copyright (c) 2005-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include +#include + + +#include "instrument_midi_io_view.h" +#include "instrument_midi_io.h" +#include "embed.h" +#include "engine.h" +#include "gui_templates.h" +#include "midi_client.h" +#include "midi_port.h" +#include "mixer.h" +#include "led_checkbox.h" +#include "lcd_spinbox.h" +#include "tab_widget.h" +#include "tooltip.h" +#include "automatable_model_templates.h" + + + +instrumentMidiIOView::instrumentMidiIOView( QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_readablePorts( NULL ), + m_writeablePorts( NULL ) +{ + m_setupTabWidget = new tabWidget( tr( "MIDI-SETUP FOR THIS CHANNEL" ), + this ); + m_setupTabWidget->setGeometry( 4, 5, 238, 200 ); + + m_inputChannelSpinBox = new lcdSpinBox( 3, m_setupTabWidget, + tr( "Input channel" ) ); + m_inputChannelSpinBox->addTextForValue( 0, "---" ); + m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + m_inputChannelSpinBox->move( 28, 52 ); + m_inputChannelSpinBox->setEnabled( FALSE ); + + + + m_outputChannelSpinBox = new lcdSpinBox( 3, m_setupTabWidget, + tr( "Output channel" ) ); + m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + m_outputChannelSpinBox->move( 28, 132 ); + m_outputChannelSpinBox->setEnabled( FALSE ); + + + m_receiveCheckBox = new ledCheckBox( tr( "Receive MIDI-events" ), + m_setupTabWidget, + tr( "Receive MIDI-events" ) ); + m_receiveCheckBox->move( 10, 34 ); + // enabling/disabling widgets is UI-stuff thus we do not use model here + connect( m_receiveCheckBox, SIGNAL( toggled( bool ) ), + m_inputChannelSpinBox, SLOT( setEnabled( bool ) ) ); + + + m_defaultVelocityInCheckBox = new ledCheckBox( + tr( "Default velocity for all input-events" ), + m_setupTabWidget, + tr( "Default input velocity" ) ); + m_defaultVelocityInCheckBox->move( 28, 84 ); + + + m_sendCheckBox = new ledCheckBox( tr( "Send MIDI-events" ), + m_setupTabWidget, + tr( "Send MIDI-events" ) ); + m_sendCheckBox->move( 10, 114 ); + connect( m_sendCheckBox, SIGNAL( toggled( bool ) ), + m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) ); + + + m_defaultVelocityOutCheckBox = new ledCheckBox( + tr( "Default velocity for all output-events" ), + m_setupTabWidget, + tr( "Default output velocity" ) ); + m_defaultVelocityOutCheckBox->move( 28, 164 ); + + + + // when using with non-raw-clients we can provide buttons showing + // our port-menus when being clicked + midiClient * mc = engine::getMixer()->getMIDIClient(); + if( mc->isRaw() == FALSE ) + { + m_readablePorts = new QMenu( m_setupTabWidget ); + m_readablePorts->setFont( pointSize<9>( + m_readablePorts->font() ) ); + connect( m_readablePorts, SIGNAL( triggered( QAction * ) ), + this, SLOT( activatedReadablePort( QAction * ) ) ); + + m_writeablePorts = new QMenu( m_setupTabWidget ); + m_writeablePorts->setFont( pointSize<9>( + m_writeablePorts->font() ) ); + connect( m_writeablePorts, SIGNAL( triggered( QAction * ) ), + this, SLOT( activatedWriteablePort( QAction * ) ) ); + + // fill menus +/* readablePortsChanged(); + writeablePortsChanged();*/ + + QToolButton * rp_btn = new QToolButton( m_setupTabWidget ); + rp_btn->setText( tr( "MIDI-devices to receive " + "MIDI-events from" ) ); + rp_btn->setIcon( embed::getIconPixmap( "midi_in" ) ); + rp_btn->setGeometry( 186, 34, 40, 40 ); + rp_btn->setMenu( m_readablePorts ); + rp_btn->setPopupMode( QToolButton::InstantPopup ); + + QToolButton * wp_btn = new QToolButton( m_setupTabWidget ); + wp_btn->setText( tr( "MIDI-devices to send MIDI-events " + "to" ) ); + wp_btn->setIcon( embed::getIconPixmap( "midi_out" ) ); + wp_btn->setGeometry( 186, 114, 40, 40 ); + wp_btn->setMenu( m_writeablePorts ); + wp_btn->setPopupMode( QToolButton::InstantPopup ); + } +} + + + + +instrumentMidiIOView::~instrumentMidiIOView() +{ +} + + + + +void instrumentMidiIOView::modelChanged( void ) +{ + instrumentMidiIO * mio = castModel(); + m_inputChannelSpinBox->setModel( &mio->m_inputChannelModel ); + m_outputChannelSpinBox->setModel( &mio->m_outputChannelModel ); + m_receiveCheckBox->setModel( &mio->m_receiveEnabledModel ); + m_defaultVelocityInCheckBox->setModel( + &mio->m_defaultVelocityInEnabledModel ); + m_sendCheckBox->setModel( &mio->m_sendEnabledModel ); + m_defaultVelocityOutCheckBox->setModel( + &mio->m_defaultVelocityOutEnabledModel ); +} + + + + +void instrumentMidiIOView::activatedReadablePort( QAction * _item ) +{ + instrumentMidiIO * mio = castModel(); + // make sure, MIDI-port is configured for input + if( _item->isChecked() == TRUE && + mio->m_midiPort->mode() != midiPort::INPUT && + mio->m_midiPort->mode() != midiPort::DUPLEX ) + { + mio->m_receiveEnabledModel.setValue( TRUE ); + } + engine::getMixer()->getMIDIClient()->subscribeReadablePort( + mio->m_midiPort, _item->text(), !_item->isChecked() ); +} + + + + +void instrumentMidiIOView::activatedWriteablePort( QAction * _item ) +{ + instrumentMidiIO * mio = castModel(); + // make sure, MIDI-port is configured for output + if( _item->isChecked() == TRUE && + mio->m_midiPort->mode() != midiPort::OUTPUT && + mio->m_midiPort->mode() != midiPort::DUPLEX ) + { + mio->m_sendEnabledModel.setValue( TRUE ); + } + engine::getMixer()->getMIDIClient()->subscribeWriteablePort( + mio->m_midiPort, _item->text(), !_item->isChecked() ); +} + + + +#include "instrument_midi_io_view.moc" + + +#endif diff --git a/src/widgets/instrument_sound_shaping_view.cpp b/src/widgets/instrument_sound_shaping_view.cpp new file mode 100644 index 0000000000..f0b97c0cfe --- /dev/null +++ b/src/widgets/instrument_sound_shaping_view.cpp @@ -0,0 +1,150 @@ +/* + * instrument_sound_shaping_view.cpp - view for instrumentSoundShaping-class + * + * Copyright (c) 2004-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 "instrument_sound_shaping_view.h" +#include "envelope_and_lfo_parameters.h" +#include "envelope_and_lfo_view.h" +#include "combobox.h" +#include "group_box.h" +#include "gui_templates.h" +#include "knob.h" +#include "tab_widget.h" + + + +const int TARGETS_TABWIDGET_X = 4; +const int TARGETS_TABWIDGET_Y = 5; +const int TARGETS_TABWIDGET_WIDTH = 238; +const int TARGETS_TABWIDGET_HEIGTH = 175; + +const int FILTER_GROUPBOX_X = TARGETS_TABWIDGET_X; +const int FILTER_GROUPBOX_Y = TARGETS_TABWIDGET_Y+TARGETS_TABWIDGET_HEIGTH+5; +const int FILTER_GROUPBOX_WIDTH = TARGETS_TABWIDGET_WIDTH; +const int FILTER_GROUPBOX_HEIGHT = 245-FILTER_GROUPBOX_Y; + + + +instrumentSoundShapingView::instrumentSoundShapingView( QWidget * _parent ) : + QWidget( _parent ), + modelView( NULL ), + m_ss( NULL ) +{ + m_targetsTabWidget = new tabWidget( tr( "TARGET" ), this ); + m_targetsTabWidget->setGeometry( TARGETS_TABWIDGET_X, + TARGETS_TABWIDGET_Y, + TARGETS_TABWIDGET_WIDTH, + TARGETS_TABWIDGET_HEIGTH ); + m_targetsTabWidget->setWhatsThis( + tr( "These tabs contain envelopes. They're very important for " + "modifying a sound, for not saying that they're almost " + "always neccessary for substractive synthesis. For " + "example if you have a volume-envelope, you can set " + "when the sound should have which volume-level. " + "Maybe you want to create some soft strings. Then your " + "sound has to fade in and out very softly. This can be " + "done by setting a large attack- and release-time. " + "It's the same for other envelope-targets like " + "panning, cutoff-frequency of used filter and so on. " + "Just monkey around with it! You can really make cool " + "sounds out of a saw-wave with just some " + "envelopes...!" ) ); + + for( int i = 0; i < instrumentSoundShaping::NumTargets; ++i ) + { + m_envLFOViews[i] = new envelopeAndLFOView( m_targetsTabWidget ); + m_targetsTabWidget->addTab( m_envLFOViews[i], + tr( __targetNames[i][0] + .toAscii().constData() ) ); + } + + + m_filterGroupBox = new groupBox( tr( "FILTER" ), this ); + m_filterGroupBox->setGeometry( FILTER_GROUPBOX_X, FILTER_GROUPBOX_Y, + FILTER_GROUPBOX_WIDTH, + FILTER_GROUPBOX_HEIGHT ); + + + m_filterComboBox = new comboBox( m_filterGroupBox, + tr( "Filter type" ) ); + m_filterComboBox->setGeometry( 14, 22, 120, 22 ); + m_filterComboBox->setFont( pointSize<8>( m_filterComboBox->font() ) ); + + m_filterComboBox->setWhatsThis( + tr( "Here you can select the built-in filter you want to use " + "for this instrument-track. Filters are very important " + "for changing the characteristics of a sound." ) ); + + + m_filterCutKnob = new knob( knobBright_26, m_filterGroupBox, + tr( "cutoff-frequency" ) ); + m_filterCutKnob->setLabel( tr( "CUTOFF" ) ); + m_filterCutKnob->move( 140, 18 ); + m_filterCutKnob->setHintText( tr( "cutoff-frequency:" ) + " ", " " + + tr( "Hz" ) ); + m_filterCutKnob->setWhatsThis( + tr( "Use this knob for setting the cutoff-frequency for the " + "selected filter. The cutoff-frequency specifies the " + "frequency for cutting the signal by a filter. For " + "example a lowpass-filter cuts all frequencies above " + "the cutoff-frequency. A highpass-filter cuts all " + "frequencies below cutoff-frequency and so on..." ) ); + + + m_filterResKnob = new knob( knobBright_26, m_filterGroupBox, + tr( "Q/Resonance" ) ); + m_filterResKnob->setLabel( tr( "Q/RESO" ) ); + m_filterResKnob->move( 190, 18 ); + m_filterResKnob->setHintText( tr( "Q/Resonance:" ) + " ", "" ); + m_filterResKnob->setWhatsThis( + tr( "Use this knob for setting Q/Resonance for the selected " + "filter. Q/Resonance tells the filter, how much it " + "should amplify frequencies near Cutoff-frequency." ) ); +} + + + + +instrumentSoundShapingView::~instrumentSoundShapingView() +{ + delete m_targetsTabWidget; +} + + + + +void instrumentSoundShapingView::modelChanged( void ) +{ + m_ss = castModel(); + m_filterGroupBox->setModel( &m_ss->m_filterEnabledModel ); + m_filterComboBox->setModel( &m_ss->m_filterModel ); + m_filterCutKnob->setModel( &m_ss->m_filterCutModel ); + m_filterResKnob->setModel( &m_ss->m_filterResModel ); + for( int i = 0; i < instrumentSoundShaping::NumTargets; ++i ) + { + m_envLFOViews[i]->setModel( m_ss->m_envLFOParameters[i] ); + } +} + + diff --git a/src/widgets/project_notes.cpp b/src/widgets/project_notes.cpp index 91745ca31b..6f73265e33 100644 --- a/src/widgets/project_notes.cpp +++ b/src/widgets/project_notes.cpp @@ -3,7 +3,7 @@ /* * project_notes.cpp - implementation of project-notes-editor * - * Copyright (c) 2005-2007 Tobias Doerffel + * Copyright (c) 2005-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -42,7 +42,7 @@ #include "embed.h" #include "engine.h" #include "main_window.h" -#include "song_editor.h" +#include "song.h" @@ -63,7 +63,7 @@ projectNotes::projectNotes( void ) : // connect( m_edit, SIGNAL( currentAlignmentChanged( int ) ), // this, SLOT( alignmentChanged( int ) ) ); connect( m_edit, SIGNAL( textChanged() ), - engine::getSongEditor(), SLOT( setModified() ) ); + engine::getSong(), SLOT( setModified() ) ); setupActions(); @@ -258,7 +258,7 @@ void projectNotes::textBold() { m_edit->setFontWeight( m_actionTextBold->isChecked() ? QFont::Bold : QFont::Normal ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -267,7 +267,7 @@ void projectNotes::textBold() void projectNotes::textUnderline() { m_edit->setFontUnderline( m_actionTextUnderline->isChecked() ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -276,7 +276,7 @@ void projectNotes::textUnderline() void projectNotes::textItalic() { m_edit->setFontItalic( m_actionTextItalic->isChecked() ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -286,7 +286,7 @@ void projectNotes::textFamily( const QString & _f ) { m_edit->setFontFamily( _f ); m_edit->viewport()->setFocus(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -296,7 +296,7 @@ void projectNotes::textSize( const QString & _p ) { m_edit->setFontPointSize( _p.toInt() ); m_edit->viewport()->setFocus(); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -354,7 +354,7 @@ void projectNotes::formatChanged( const QTextCharFormat & _f ) pix.fill( _f.foreground().color() ); m_actionTextColor->setIcon( pix ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -378,7 +378,7 @@ void projectNotes::alignmentChanged( int _a ) { m_actionAlignJustify->setChecked( TRUE ); } - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } diff --git a/src/widgets/tempo_sync_knob.cpp b/src/widgets/tempo_sync_knob.cpp index 2173b68d99..fe71b14725 100644 --- a/src/widgets/tempo_sync_knob.cpp +++ b/src/widgets/tempo_sync_knob.cpp @@ -4,7 +4,7 @@ * tempo_sync_knob.cpp - adds bpm to ms conversion for knob class * * Copyright (c) 2005-2007 Danny McRae - * Copyright (c) 2005-2007 Tobias Doerffel + * Copyright (c) 2005-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -37,7 +37,7 @@ #include "embed.h" #include "main_window.h" #include "meter_dialog.h" -#include "song_editor.h" +#include "song.h" tempoSyncKnob::tempoSyncKnob( int _knob_num, QWidget * _parent, @@ -50,7 +50,7 @@ tempoSyncKnob::tempoSyncKnob( int _knob_num, QWidget * _parent, m_tempoSyncDescription( tr( "Tempo Sync" ) ), m_tempoLastSyncMode( NO_SYNC ) { - connect( engine::getSongEditor(), SIGNAL( tempoChanged( bpm_t ) ), + connect( engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), this, SLOT( calculateTempoSyncTime( bpm_t ) ) ); m_custom = new meterDialog( engine::getMainWindow()->workspace(), NULL ); @@ -93,7 +93,7 @@ void tempoSyncKnob::contextMenuEvent( QContextMenuEvent * ) this, SLOT( pasteValue() ) ); contextMenu.addSeparator(); - float limit = 60000.0f / ( engine::getSongEditor()->getTempo() * + float limit = 60000.0f / ( engine::getSong()->getTempo() * m_scale ); QMenu * syncMenu = contextMenu.addMenu( m_tempoSyncIcon, @@ -173,7 +173,7 @@ void tempoSyncKnob::contextMenuEvent( QContextMenuEvent * ) void tempoSyncKnob::mouseMoveEvent( QMouseEvent * _me ) { m_tempoSyncMode = NO_SYNC; - calculateTempoSyncTime( engine::getSongEditor()->getTempo() ); + calculateTempoSyncTime( engine::getSong()->getTempo() ); knob::mouseMoveEvent( _me ); } @@ -184,7 +184,7 @@ void tempoSyncKnob::wheelEvent( QWheelEvent * _we ) { knob::wheelEvent( _we ); m_tempoSyncMode = NO_SYNC; - calculateTempoSyncTime( engine::getSongEditor()->getTempo() ); + calculateTempoSyncTime( engine::getSong()->getTempo() ); } @@ -201,7 +201,7 @@ void tempoSyncKnob::setTempoSync( QAction * _item ) void tempoSyncKnob::setTempoSync( int _note_type ) { setSyncMode( ( tempoSyncMode ) _note_type ); - engine::getSongEditor()->setModified(); + engine::getSong()->setModified(); } @@ -380,7 +380,7 @@ void tempoSyncKnob::setSyncMode( tempoSyncMode _new_mode ) this, SLOT( updateCustom() ) ); } } - calculateTempoSyncTime( engine::getSongEditor()->getTempo() ); + calculateTempoSyncTime( engine::getSong()->getTempo() ); } @@ -397,7 +397,7 @@ float tempoSyncKnob::getScale( void ) void tempoSyncKnob::setScale( float _new_scale ) { m_scale = _new_scale; - calculateTempoSyncTime( engine::getSongEditor()->getTempo() ); + calculateTempoSyncTime( engine::getSong()->getTempo() ); emit scaleChanged( _new_scale ); }