From 26a84837c250c5040296f89c8deefe16eefdeed4 Mon Sep 17 00:00:00 2001 From: "Raine M. Ekman" Date: Wed, 14 Jan 2015 22:01:42 +0200 Subject: [PATCH 01/59] Switch track imported from MIDI channel 10 to bank 128, patch 0 in SF2 player. (aka. import drum tracks) --- plugins/MidiImport/MidiImport.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index ec3178d85..67e7ba3b4 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -497,6 +497,15 @@ bool MidiImport::readSMF( TrackContainer* tc ) } } + // Set channel 10 to drums as per General MIDI's orders + if( chs[9].hasNotes && chs[9].it_inst && chs[9].isSF2 ) + { + // AFAIK, 128 should be the standard bank for drums in SF2. + // If not, this has to be made configurable. + chs[9].it_inst->childModel( "bank" )->setValue( 128 ); + chs[9].it_inst->childModel( "patch" )->setValue( 0 ); + } + return true; } From b3d943920c583f9e165c455f74fdced311583697 Mon Sep 17 00:00:00 2001 From: Dave French Date: Sun, 18 Jan 2015 19:16:43 +0000 Subject: [PATCH 02/59] proposed fix 821 Range-select in Song Editor --- include/TimeLineWidget.h | 6 +++++- include/TrackContainerView.h | 20 ++++++++++++++++++++ src/gui/TimeLineWidget.cpp | 16 +++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/TimeLineWidget.h b/include/TimeLineWidget.h index abf622aaf..4c70bc0ea 100644 --- a/include/TimeLineWidget.h +++ b/include/TimeLineWidget.h @@ -35,6 +35,7 @@ class QPixmap; class QToolBar; class NStateButton; class TextFloat; +class SongEditor; class TimeLineWidget : public QWidget, public JournallingObject @@ -171,6 +172,8 @@ private: TextFloat * m_hint; + SongEditor *m_songEditor; + int m_initalXSelect; enum actions @@ -178,7 +181,8 @@ private: NoAction, MovePositionMarker, MoveLoopBegin, - MoveLoopEnd + MoveLoopEnd, + SelectSongTCO, } m_action; int m_moveXOff; diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index fdf28be91..f4ee969d1 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -92,6 +92,26 @@ public: return( QVector() ); } + /// + /// \brief selectRegionFromPixels + /// \param x + /// \param y + /// Use the rubber band to select TCO from all tracks using x, y pixels + void selectRegionFromPixels(int x, int y) + { + m_rubberBand->setEnabled( true ); + m_rubberBand->show(); + m_rubberBand->setGeometry( min( x, y ), 0, max( x, y ) - min( x, y ), std::numeric_limits::max() ); + } + + /// + /// \brief stopRubberBand + /// Removes the rubber band from display when finished with. + void stopRubberBand() + { + m_rubberBand->hide(); + m_rubberBand->setEnabled( false ); + } TrackContainer* model() { diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 5966e7d51..94a7756b2 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -39,6 +39,7 @@ #include "NStateButton.h" #include "GuiApplication.h" #include "TextFloat.h" +#include "SongEditor.h" #if QT_VERSION < 0x040800 @@ -105,6 +106,7 @@ TimeLineWidget::TimeLineWidget( const int _xoff, const int _yoff, const float _p connect( update_timer, SIGNAL( timeout() ), this, SLOT( updatePosition() ) ); update_timer->start( 50 ); + m_songEditor = dynamic_cast(_parent); } @@ -280,7 +282,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) { return; } - if( event->button() == Qt::LeftButton ) + if( event->button() == Qt::LeftButton && !(event->modifiers() & Qt::ShiftModifier) ) { m_action = MovePositionMarker; if( event->x() - m_xOffset < s_posMarkerPixmap->width() ) @@ -292,6 +294,11 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) m_moveXOff = s_posMarkerPixmap->width() / 2; } } + else if( event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier) && m_songEditor ) + { + m_action = SelectSongTCO; + m_initalXSelect = event->x(); + } else if( event->button() == Qt::RightButton || event->button() == Qt::MiddleButton ) { m_moveXOff = s_posMarkerPixmap->width() / 2; @@ -373,6 +380,12 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) update(); break; } + case SelectSongTCO: + if( m_songEditor ) + { + m_songEditor->selectRegionFromPixels( m_initalXSelect , event->x() ); + } + break; default: break; @@ -386,6 +399,7 @@ void TimeLineWidget::mouseReleaseEvent( QMouseEvent* event ) { delete m_hint; m_hint = NULL; + if(m_action == SelectSongTCO && m_songEditor ) { m_songEditor->stopRubberBand(); } m_action = NoAction; } From 71bab17233fea1ced67edbd9771b2cdee271fe7c Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Sun, 18 Jan 2015 15:50:17 -0800 Subject: [PATCH 03/59] Work on codestyle and readability --- include/Plugin.h | 10 ++++--- include/lmms_basics.h | 6 ++-- src/gui/MainWindow.cpp | 56 +++++++++++++++++------------------- src/gui/PluginBrowser.cpp | 7 +---- src/gui/embed.cpp | 49 +++++++++++++++---------------- src/gui/widgets/SideBar.cpp | 57 +++++++++++++++++++------------------ 6 files changed, 89 insertions(+), 96 deletions(-) diff --git a/include/Plugin.h b/include/Plugin.h index b73238ab5..40a075c67 100644 --- a/include/Plugin.h +++ b/include/Plugin.h @@ -134,7 +134,7 @@ public: const Plugin::PluginTypes m_type; } ; - SubPluginFeatures * subPluginFeatures; + SubPluginFeatures *subPluginFeatures; } ; @@ -148,7 +148,9 @@ public: // returns display-name out of descriptor virtual QString displayName() const { - return Model::displayName().isEmpty() ? m_descriptor->displayName : Model::displayName(); + return Model::displayName().isEmpty() + ? m_descriptor->displayName + : Model::displayName(); } // return plugin-type @@ -173,13 +175,13 @@ public: // returns an instance of a plugin whose name matches to given one // if specified plugin couldn't be loaded, it creates a dummy-plugin - static Plugin * instantiate( const QString& pluginName, Model * parent, void * data ); + static Plugin * instantiate( const QString& pluginName, Model *parent, void * data ); // fills given list with descriptors of all available plugins static void getDescriptorsOfAvailPlugins( DescriptorList& pluginDescriptors ); // create a view for the model - PluginView * createView( QWidget* parent ); + PluginView* createView( QWidget* parent ); protected: diff --git a/include/lmms_basics.h b/include/lmms_basics.h index bdd72f4fa..082415124 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -97,13 +97,13 @@ inline float typeInfo::minEps() } template<> -inline bool typeInfo::isEqual( float _x, float _y ) +inline bool typeInfo::isEqual( float x, float y ) { - if( likely( _x == _y ) ) + if( unlikely( x == y ) ) { return true; } - return absVal( _x - _y ) < minEps(); + return absVal( x - y ) < minEps(); } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 612a7409e..22de85bc4 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -94,24 +94,25 @@ MainWindow::MainWindow() : QSplitter * splitter = new QSplitter( Qt::Horizontal, w ); splitter->setChildrenCollapsible( false ); - QString wdir = ConfigManager::inst()->workingDir(); + ConfigManager* confMgr = ConfigManager::inst(); + QString wdir = confMgr->workingDir(); sideBar->appendTab( new PluginBrowser( splitter ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userProjectsDir() + "*" + - ConfigManager::inst()->factoryProjectsDir(), + confMgr->userProjectsDir() + "*" + + confMgr->factoryProjectsDir(), "*.mmp *.mmpz *.xml *.mid *.flp", tr( "My Projects" ), embed::getIconPixmap( "project_file" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userSamplesDir() + "*" + - ConfigManager::inst()->factorySamplesDir(), + confMgr->userSamplesDir() + "*" + + confMgr->factorySamplesDir(), "*", tr( "My Samples" ), embed::getIconPixmap( "sample_file" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userPresetsDir() + "*" + - ConfigManager::inst()->factoryPresetsDir(), + confMgr->userPresetsDir() + "*" + + confMgr->factoryPresetsDir(), "*.xpf *.cs.xml *.xiz", tr( "My Presets" ), embed::getIconPixmap( "preset_file" ).transformed( QTransform().rotate( 90 ) ), @@ -121,33 +122,30 @@ MainWindow::MainWindow() : embed::getIconPixmap( "home" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); + QStringList root_paths; + QString title = tr( "Root directory" ); + bool dirs_as_items = false; + #ifdef LMMS_BUILD_APPLE + title = tr( "Volumes" ); root_paths += "/Volumes"; -#else +#elif defined(LMMS_BUILD_WIN32) + title = tr( "My Computer" ); + dirs_as_items = true; +#endif + +#if ! defined(LMMS_BUILD_APPLE) QFileInfoList drives = QDir::drives(); foreach( const QFileInfo & drive, drives ) { root_paths += drive.absolutePath(); } #endif - sideBar->appendTab( new FileBrowser( root_paths.join( "*" ), "*", -#ifdef LMMS_BUILD_WIN32 - tr( "My Computer" ), -#elif defined(LMMS_BUILD_APPLE) - tr( "Volumes" ), -#else - tr( "Root Directory" ), -#endif + sideBar->appendTab( new FileBrowser( root_paths.join( "*" ), "*", title, embed::getIconPixmap( "computer" ).transformed( QTransform().rotate( 90 ) ), - splitter, -#ifdef LMMS_BUILD_WIN32 - true -#else - false -#endif - ) ); + splitter, dirs_as_items) ); m_workspace = new QMdiArea( splitter ); @@ -190,13 +188,13 @@ MainWindow::MainWindow() : vbox->addWidget( w ); setCentralWidget( main_widget ); - m_updateTimer.start( 1000 / 20, this ); // 20 fps + m_updateTimer.start( 1000 / 20, this ); // 20 fps if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() ) { // connect auto save connect(&m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSave())); - m_autoSaveTimer.start(1000 * 60); // 1 minute + m_autoSaveTimer.start(1000 * 60); // 1 minute } connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), @@ -208,12 +206,10 @@ MainWindow::MainWindow() : MainWindow::~MainWindow() { - for( QList::iterator it = m_tools.begin(); - it != m_tools.end(); ++it ) + for( PluginView *view : m_tools ) { - Model * m = ( *it )->model(); - delete *it; - delete m; + delete view; + delete view->model(); } // TODO: Close tools // destroy engine which will do further cleanups etc. diff --git a/src/gui/PluginBrowser.cpp b/src/gui/PluginBrowser.cpp index 5c10dd368..96f33ae75 100644 --- a/src/gui/PluginBrowser.cpp +++ b/src/gui/PluginBrowser.cpp @@ -88,8 +88,6 @@ PluginBrowser::~PluginBrowser() - - PluginDescList::PluginDescList(QWidget *parent) : QWidget(parent) { @@ -98,7 +96,6 @@ PluginDescList::PluginDescList(QWidget *parent) : Plugin::getDescriptorsOfAvailPlugins( m_pluginDescriptors ); std::sort(m_pluginDescriptors.begin(), m_pluginDescriptors.end(), pluginBefore); - for( Plugin::DescriptorList::const_iterator it = m_pluginDescriptors.constBegin(); it != m_pluginDescriptors.constEnd(); ++it ) { @@ -117,8 +114,6 @@ PluginDescList::PluginDescList(QWidget *parent) : - - PluginDescWidget::PluginDescWidget( const Plugin::Descriptor & _pd, QWidget * _parent ) : QWidget( _parent ), @@ -181,7 +176,6 @@ void PluginDescWidget::paintEvent( QPaintEvent * ) m_targetHeight = qMax( 60, 25 + br.height() ); } } - } @@ -237,6 +231,7 @@ void PluginDescWidget::updateHeight() m_updateTimer.stop(); return; } + if( !m_updateTimer.isActive() ) { m_updateTimer.start( 15 ); diff --git a/src/gui/embed.cpp b/src/gui/embed.cpp index 08af0c0a2..4e6ecaa13 100644 --- a/src/gui/embed.cpp +++ b/src/gui/embed.cpp @@ -45,73 +45,70 @@ namespace #include "embedded_resources.h" -QPixmap getIconPixmap( const char * _name, int _w, int _h ) +QPixmap getIconPixmap( const char * pixmapName, int width, int height ) { - if( _w == -1 || _h == -1 ) + if( width == -1 || height == -1 ) { - // Return cached pixmap - QPixmap cached = s_pixmapCache.value( _name ); + // Return cached pixmap + QPixmap cached = s_pixmapCache.value( pixmapName ); if( !cached.isNull() ) { return cached; } // Or try to load it - QList formats = - QImageReader::supportedImageFormats(); + QList formats = QImageReader::supportedImageFormats(); QList candidates; - QPixmap p; + QPixmap pixmap; QString name; int i; - for ( i = 0; i < formats.size() && p.isNull(); ++i ) + for ( i = 0; i < formats.size() && pixmap.isNull(); ++i ) { - candidates << QString( _name ) + "." + formats.at( i ).data(); + candidates << QString( pixmapName ) + "." + formats.at( i ).data(); } #ifdef PLUGIN_NAME - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->artworkDir() + "plugins/" + + pixmap = QPixmap( ConfigManager::inst()->artworkDir() + "plugins/" + STRINGIFY( PLUGIN_NAME ) + "_" + name ); } #endif - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->artworkDir() + name ); + pixmap = QPixmap( ConfigManager::inst()->artworkDir() + name ); } // nothing found, so look in default-artwork-dir - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->defaultArtworkDir() - + name ); + pixmap = QPixmap( ConfigManager::inst()->defaultArtworkDir() + name ); } - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); const embed::descriptor & e = findEmbeddedData( name.toUtf8().constData() ); // found? - if( QString( e.name ) == name ) + if( name == e.name ) { - p.loadFromData( e.data, e.size ); + pixmap.loadFromData( e.data, e.size ); } } // Fallback - if(p.isNull()) + if( pixmap.isNull() ) { - p = QPixmap( 1, 1 ); + pixmap = QPixmap( 1, 1 ); } // Save to cache and return - s_pixmapCache.insert( _name, p ); - return p; - + s_pixmapCache.insert( pixmapName, pixmap ); + return pixmap; } - return getIconPixmap( _name ). - scaled( _w, _h, Qt::IgnoreAspectRatio, + return getIconPixmap( pixmapName ). + scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); } diff --git a/src/gui/widgets/SideBar.cpp b/src/gui/widgets/SideBar.cpp index 409fbf771..990bae7f6 100644 --- a/src/gui/widgets/SideBar.cpp +++ b/src/gui/widgets/SideBar.cpp @@ -107,53 +107,56 @@ SideBar::~SideBar() -void SideBar::appendTab( SideBarWidget * _sbw ) +void SideBar::appendTab( SideBarWidget *widget ) { - SideBarButton * btn = new SideBarButton( orientation(), this ); - btn->setText( _sbw->title() ); - btn->setIcon( _sbw->icon() ); - btn->setCheckable( true ); - m_widgets[btn] = _sbw; - m_btnGroup.addButton( btn ); - addWidget( btn ); + SideBarButton *button = new SideBarButton( orientation(), this ); + button->setText( widget->title() ); + button->setIcon( widget->icon() ); + button->setCheckable( true ); + m_widgets[button] = widget; + m_btnGroup.addButton( button ); + addWidget( button ); - _sbw->hide(); - _sbw->setMinimumWidth( 200 ); + widget->hide(); + widget->setMinimumWidth( 200 ); - ToolTip::add( btn, _sbw->title() ); + ToolTip::add( button, widget->title() ); } -void SideBar::toggleButton( QAbstractButton * _btn ) +void SideBar::toggleButton( QAbstractButton * button ) { - QToolButton * toolButton = NULL; - QWidget * activeWidget = NULL; - for( ButtonMap::Iterator it = m_widgets.begin(); - it != m_widgets.end(); ++it ) + QToolButton *toolButton = NULL; + QWidget *activeWidget = NULL; + + for( auto it = m_widgets.begin(); it != m_widgets.end(); ++it ) { - QToolButton * curBtn = it.key(); - if( curBtn != _btn ) + QToolButton *curBtn = it.key(); + QWidget *curWidget = it.value(); + + if( curBtn == button ) + { + toolButton = curBtn; + activeWidget = curWidget; + } + else { curBtn->setChecked( false ); curBtn->setToolButtonStyle( Qt::ToolButtonIconOnly ); } - else + + if( curWidget ) { - toolButton = it.key(); - activeWidget = it.value(); - } - if( it.value() ) - { - it.value()->hide(); + curWidget->hide(); } } if( toolButton && activeWidget ) { - activeWidget->setVisible( _btn->isChecked() ); - toolButton->setToolButtonStyle( _btn->isChecked() ? + activeWidget->setVisible( button->isChecked() ); + toolButton->setToolButtonStyle( button->isChecked() ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly ); } } From 7777fc73426afb08b621d5ed5a3a1382dcd7e413 Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 19:44:23 -0800 Subject: [PATCH 04/59] Remove unused variable --- src/gui/MainWindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 22de85bc4..255d79613 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -83,7 +83,6 @@ MainWindow::MainWindow() : vbox->setSpacing( 0 ); vbox->setMargin( 0 ); - QWidget * w = new QWidget( main_widget ); QHBoxLayout * hbox = new QHBoxLayout( w ); hbox->setSpacing( 0 ); @@ -95,7 +94,7 @@ MainWindow::MainWindow() : splitter->setChildrenCollapsible( false ); ConfigManager* confMgr = ConfigManager::inst(); - QString wdir = confMgr->workingDir(); + sideBar->appendTab( new PluginBrowser( splitter ) ); sideBar->appendTab( new FileBrowser( confMgr->userProjectsDir() + "*" + From f148fc34b44861334af8ee7be4a29148a966b10a Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 20:24:18 -0800 Subject: [PATCH 05/59] Don't access deleted memory --- src/gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 255d79613..cccc7bd39 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -207,8 +207,8 @@ MainWindow::~MainWindow() { for( PluginView *view : m_tools ) { - delete view; delete view->model(); + delete view; } // TODO: Close tools // destroy engine which will do further cleanups etc. From 8c76af18067601a90bcddb8a9b17df69ba8c825e Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 20:26:11 -0800 Subject: [PATCH 06/59] Remove premature optimization in float comparison --- include/lmms_basics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lmms_basics.h b/include/lmms_basics.h index 082415124..a0c8274d4 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -99,7 +99,7 @@ inline float typeInfo::minEps() template<> inline bool typeInfo::isEqual( float x, float y ) { - if( unlikely( x == y ) ) + if( x == y ) { return true; } From deb3e45791f0687cf78db8900011a1d4f6513455 Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 20:26:33 -0800 Subject: [PATCH 07/59] More code style fixes --- include/lmms_basics.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/lmms_basics.h b/include/lmms_basics.h index a0c8274d4..ea02f77d1 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -78,9 +78,9 @@ struct typeInfo return 1; } - static inline bool isEqual( T _x, T _y ) + static inline bool isEqual( T x, T y ) { - return _x == _y; + return x == y; } static inline T absVal( T t ) From a74ff27d3527d18c553515fbb0e93713d2e396b7 Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 20:37:32 -0800 Subject: [PATCH 08/59] Remove usage of 'auto' --- src/gui/editors/PianoRoll.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index d837292b7..928752ace 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -375,7 +375,8 @@ PianoRoll::PianoRoll() : this, SLOT( quantizeChanged() ) ); // Set up scale model - const auto& chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance(); + const InstrumentFunctionNoteStacking::ChordTable& chord_table = + InstrumentFunctionNoteStacking::ChordTable::getInstance(); m_scaleModel.addItem( tr("No scale") ); for( const InstrumentFunctionNoteStacking::Chord& chord : chord_table ) @@ -3814,7 +3815,8 @@ int PianoRoll::quantization() const void PianoRoll::updateSemiToneMarkerMenu() { - const auto& chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance(); + const InstrumentFunctionNoteStacking::ChordTable& chord_table = + InstrumentFunctionNoteStacking::ChordTable::getInstance(); const InstrumentFunctionNoteStacking::Chord& scale = chord_table.getScaleByName( m_scaleModel.currentText() ); const InstrumentFunctionNoteStacking::Chord& chord = From 52ec4722fb1c00fed175ed94e7840acb308e17e3 Mon Sep 17 00:00:00 2001 From: Jonas Trappenberg Date: Tue, 20 Jan 2015 20:37:58 -0800 Subject: [PATCH 09/59] Add explanation to acronym variable --- include/PianoRoll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index bc2a0d8cb..8f1dabdc3 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -295,7 +295,7 @@ private: int m_oldNotesEditHeight; int m_notesEditHeight; - int m_ppt; + int m_ppt; // pixels per tact int m_totalKeysToScroll; // remember these values to use them From 1cf9300f72db9e4f6c6f4ce075f6465cb3fd0a19 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 21 Jan 2015 11:55:30 +0000 Subject: [PATCH 10/59] 821 changed to use sockets/ slots --- include/TimeLineWidget.h | 6 +++++- include/TrackContainerView.h | 31 +++++++++++-------------------- src/gui/TimeLineWidget.cpp | 10 +++------- src/gui/TrackContainerView.cpp | 13 +++++++++++++ src/gui/editors/SongEditor.cpp | 4 ++++ 5 files changed, 36 insertions(+), 28 deletions(-) diff --git a/include/TimeLineWidget.h b/include/TimeLineWidget.h index 4c70bc0ea..37e1f6ee7 100644 --- a/include/TimeLineWidget.h +++ b/include/TimeLineWidget.h @@ -129,6 +129,11 @@ public: m_ppt / MidiTime::ticksPerTact() ); } +signals: + + void regionSelectedFromPixels( int, int ); + void selectionFinished(); + public slots: void updatePosition( const MidiTime & ); @@ -172,7 +177,6 @@ private: TextFloat * m_hint; - SongEditor *m_songEditor; int m_initalXSelect; diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index f4ee969d1..51b8ca0fa 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -92,26 +92,6 @@ public: return( QVector() ); } - /// - /// \brief selectRegionFromPixels - /// \param x - /// \param y - /// Use the rubber band to select TCO from all tracks using x, y pixels - void selectRegionFromPixels(int x, int y) - { - m_rubberBand->setEnabled( true ); - m_rubberBand->show(); - m_rubberBand->setGeometry( min( x, y ), 0, max( x, y ) - min( x, y ), std::numeric_limits::max() ); - } - - /// - /// \brief stopRubberBand - /// Removes the rubber band from display when finished with. - void stopRubberBand() - { - m_rubberBand->hide(); - m_rubberBand->setEnabled( false ); - } TrackContainer* model() { @@ -146,6 +126,17 @@ public slots: virtual void dropEvent( QDropEvent * _de ); virtual void dragEnterEvent( QDragEnterEvent * _dee ); + /// + /// \brief selectRegionFromPixels + /// \param x + /// \param y + /// Use the rubber band to select TCO from all tracks using x, y pixels + void selectRegionFromPixels(int x, int y); + + /// + /// \brief stopRubberBand + /// Removes the rubber band from display when finished with. + void stopRubberBand(); protected: static const int DEFAULT_PIXELS_PER_TACT = 16; diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 94a7756b2..4ab508c9c 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -106,7 +106,6 @@ TimeLineWidget::TimeLineWidget( const int _xoff, const int _yoff, const float _p connect( update_timer, SIGNAL( timeout() ), this, SLOT( updatePosition() ) ); update_timer->start( 50 ); - m_songEditor = dynamic_cast(_parent); } @@ -294,7 +293,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) m_moveXOff = s_posMarkerPixmap->width() / 2; } } - else if( event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier) && m_songEditor ) + else if( event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier) ) { m_action = SelectSongTCO; m_initalXSelect = event->x(); @@ -381,10 +380,7 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) break; } case SelectSongTCO: - if( m_songEditor ) - { - m_songEditor->selectRegionFromPixels( m_initalXSelect , event->x() ); - } + emit regionSelectedFromPixels( m_initalXSelect , event->x() ); break; default: @@ -399,7 +395,7 @@ void TimeLineWidget::mouseReleaseEvent( QMouseEvent* event ) { delete m_hint; m_hint = NULL; - if(m_action == SelectSongTCO && m_songEditor ) { m_songEditor->stopRubberBand(); } + if ( m_action == SelectSongTCO ) { emit selectionFinished(); } m_action = NoAction; } diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index a2d3ce12b..8872512c9 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -313,6 +313,19 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) arg( Track::SampleTrack ) ); } +void TrackContainerView::selectRegionFromPixels(int x, int y) +{ + m_rubberBand->setEnabled( true ); + m_rubberBand->show(); + m_rubberBand->setGeometry( min( x, y ), 0, max( x, y ) - min( x, y ), std::numeric_limits::max() ); +} + +void TrackContainerView::stopRubberBand() +{ + m_rubberBand->hide(); + m_rubberBand->setEnabled( false ); +} + diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 900b936a5..4186c3a0b 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -98,6 +98,10 @@ SongEditor::SongEditor( Song * _song ) : SLOT( updatePosition( const MidiTime & ) ) ); connect( m_timeLine, SIGNAL( positionChanged( const MidiTime & ) ), this, SLOT( updatePosition( const MidiTime & ) ) ); + connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), + this, SLOT( selectRegionFromPixels( int, int ) ) ); + connect( m_timeLine, SIGNAL( selectionFinished() ), + this, SLOT( stopRubberBand() ) ); m_positionLine = new positionLine( this ); From d6ff1a7086604c7d6da595bf44204f1a01842b44 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Wed, 21 Jan 2015 13:33:25 +0100 Subject: [PATCH 11/59] Fix BB Editor project load Closes #1621 --- include/BBEditor.h | 8 ++++---- src/gui/editors/BBEditor.cpp | 30 ++++++++++++------------------ 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/BBEditor.h b/include/BBEditor.h index abd325bc2..aea2f8763 100644 --- a/include/BBEditor.h +++ b/include/BBEditor.h @@ -57,9 +57,6 @@ public slots: void play(); void stop(); -protected: - virtual void closeEvent( QCloseEvent * _ce ); - private: BBTrackContainerView* m_trackContainerView; ComboBox * m_bbComboBox; @@ -80,13 +77,16 @@ public: void removeBBView(int bb); + void saveSettings(QDomDocument& doc, QDomElement& element); + void loadSettings(const QDomElement& element); + public slots: void addSteps(); void removeSteps(); void addAutomationTrack(); protected slots: - virtual void dropEvent(QDropEvent * de ); + void dropEvent(QDropEvent * de ); void updatePosition(); private: diff --git a/src/gui/editors/BBEditor.cpp b/src/gui/editors/BBEditor.cpp index 667b88545..02ea125de 100644 --- a/src/gui/editors/BBEditor.cpp +++ b/src/gui/editors/BBEditor.cpp @@ -156,8 +156,6 @@ void BBEditor::stop() - - BBTrackContainerView::BBTrackContainerView(BBTrackContainer* tc) : TrackContainerView(tc), m_bbtc(tc) @@ -168,8 +166,6 @@ BBTrackContainerView::BBTrackContainerView(BBTrackContainer* tc) : - - void BBTrackContainerView::addSteps() { TrackContainer::TrackList tl = model()->tracks(); @@ -224,6 +220,18 @@ void BBTrackContainerView::removeBBView(int bb) +void BBTrackContainerView::saveSettings(QDomDocument& doc, QDomElement& element) +{ + MainWindow::saveWidgetState(parentWidget(), element); +} + +void BBTrackContainerView::loadSettings(const QDomElement& element) +{ + MainWindow::restoreWidgetState(parentWidget(), element); +} + + + void BBTrackContainerView::dropEvent(QDropEvent* de) { @@ -254,17 +262,3 @@ void BBTrackContainerView::updatePosition() //realignTracks(); emit positionChanged( m_currentPosition ); } - -void BBEditor::closeEvent( QCloseEvent * _ce ) - { - if( parentWidget() ) - { - parentWidget()->hide(); - } - else - { - hide(); - } - _ce->ignore(); - } - From 9460fdec9b857f115761454042c2a8ac17a8c819 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 21 Jan 2015 13:18:01 +0000 Subject: [PATCH 12/59] Proposed fix 1643 Allow drag-and-drop of project files --- src/gui/FileBrowser.cpp | 4 ++++ src/gui/TrackContainerView.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index fd86ffc84..0d19ec6aa 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -518,6 +518,10 @@ void FileBrowserTreeWidget::mouseMoveEvent( QMouseEvent * me ) new StringPairDrag( "importedproject", f->fullName(), embed::getIconPixmap( "midi_file" ), this ); break; + case FileItem::ProjectFile: + new StringPairDrag( "projectfile", f->fullName(), + embed::getIconPixmap( "project_file" ), this ); + break; default: break; diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index a2d3ce12b..d8c3a5c40 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -307,7 +307,7 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) { StringPairDrag::processDragEnterEvent( _dee, QString( "presetfile,pluginpresetfile,samplefile,instrument," - "importedproject,soundfontfile,vstpluginfile," + "importedproject,soundfontfile,vstpluginfile,projectfile," "track_%1,track_%2" ). arg( Track::InstrumentTrack ). arg( Track::SampleTrack ) ); @@ -360,6 +360,13 @@ void TrackContainerView::dropEvent( QDropEvent * _de ) ImportFilter::import( value, m_tc ); _de->accept(); } + + else if( type == "projectfile") + { + Engine::getSong()->loadProject( value ); + _de->accept(); + } + else if( type.left( 6 ) == "track_" ) { DataFile dataFile( value.toUtf8() ); From e63bd848d083697fc3f245b5d5d592b78d228cbe Mon Sep 17 00:00:00 2001 From: Lukas W Date: Thu, 22 Jan 2015 11:30:57 +0100 Subject: [PATCH 13/59] PianoRoll: Fix faulty rename Fix a renaming mistake made in 1d07a91a83dabb4ce8f6a7e2738b273618ae8c4e --- src/gui/editors/PianoRoll.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 928752ace..366920df7 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -3378,11 +3378,11 @@ void PianoRoll::finishRecordNote(const Note & n ) { if( it->key() == n.key() ) { - Note n( n.length(), it->pos(), + Note n1( n.length(), it->pos(), it->key(), it->getVolume(), it->getPanning() ); - n.quantizeLength( quantization() ); - m_pattern->addNote( n ); + n1.quantizeLength( quantization() ); + m_pattern->addNote( n1 ); update(); m_recordingNotes.erase( it ); break; From 9cc1a5931c34535436a2fb82e51031121b3a53d1 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Thu, 22 Jan 2015 12:39:20 +0100 Subject: [PATCH 14/59] Make -Werror optional --- .travis/linux..script.sh | 2 +- .travis/linux.win32.script.sh | 1 + .travis/linux.win64.script.sh | 1 + .travis/osx..script.sh | 2 +- CMakeLists.txt | 3 ++- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis/linux..script.sh b/.travis/linux..script.sh index d89b130db..c9de77d36 100644 --- a/.travis/linux..script.sh +++ b/.travis/linux..script.sh @@ -1 +1 @@ -cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_WERROR=ON .. diff --git a/.travis/linux.win32.script.sh b/.travis/linux.win32.script.sh index 3831a842f..b0743d295 100644 --- a/.travis/linux.win32.script.sh +++ b/.travis/linux.win32.script.sh @@ -1 +1,2 @@ +export CMAKE_OPTS="-DUSE_WERROR=ON" ../build_mingw32 || ../build_mingw32 diff --git a/.travis/linux.win64.script.sh b/.travis/linux.win64.script.sh index 7c6c4f96a..ba79da8ca 100644 --- a/.travis/linux.win64.script.sh +++ b/.travis/linux.win64.script.sh @@ -1 +1,2 @@ +export CMAKE_OPTS="-DUSE_WERROR=ON" ../build_mingw64 || ../build_mingw64 diff --git a/.travis/osx..script.sh b/.travis/osx..script.sh index d89b130db..d594e58f6 100644 --- a/.travis/osx..script.sh +++ b/.travis/osx..script.sh @@ -1 +1 @@ -cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. -DUSE_WERROR=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cb740777..a526df3df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,7 +358,8 @@ CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/plugins/zynaddsubfx/zynaddsubfx.rc.in" "${CM # set compiler flags SET(WERROR_FLAGS "-Wall -Werror=unused-function -Wno-sign-compare -Wno-strict-overflow") -IF(NOT LMMS_BUILD_APPLE) +OPTION(USE_WERROR "Add -werror to the build flags. Stops the build on warnings" OFF) +IF(${USE_WERROR}) SET(WERROR_FLAGS "${WERROR_FLAGS} -Werror") ENDIF() From 4dd40e17556b09082db14a69bf602fbbd245227a Mon Sep 17 00:00:00 2001 From: Lukas W Date: Thu, 22 Jan 2015 12:53:38 +0100 Subject: [PATCH 15/59] Fix missed rename note->Note Fixes #1464 Bug introduced in aaeb5216ad3f951be89aa2dcad437f0320a4597d --- src/core/Song.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 3dfa1fbd0..7198416cc 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -116,7 +116,7 @@ Song::Song() : /* connect( &m_masterPitchModel, SIGNAL( dataChanged() ), this, SLOT( masterPitchChanged() ) );*/ - qRegisterMetaType( "note" ); + qRegisterMetaType( "Note" ); setType( SongContainer ); } From df9d495571902cb739cecc8f37f5b8cd35366bda Mon Sep 17 00:00:00 2001 From: Lukas W Date: Thu, 22 Jan 2015 16:28:29 +0100 Subject: [PATCH 16/59] Some #include cleanups --- include/AutomatableModel.h | 19 ++- include/BBTrackContainer.h | 2 +- include/BandLimitedWave.h | 6 +- include/BufferManager.h | 13 +- include/ComboBoxModel.h | 1 - include/DataFile.h | 4 +- include/DrumSynth.h | 6 +- include/Engine.h | 11 -- include/Instrument.h | 11 +- include/MemoryManager.h | 3 +- include/MixerWorkerThread.h | 12 +- include/Model.h | 2 +- include/ModelView.h | 1 + include/NotePlayHandle.h | 11 +- include/Oscillator.h | 2 - include/fft_helpers.h | 1 - src/core/AutomatableModel.cpp | 25 ++-- src/core/AutomationPattern.cpp | 15 +-- src/core/BBTrackContainer.cpp | 4 +- src/core/BandLimitedWave.cpp | 25 ++-- src/core/BufferManager.cpp | 14 +- src/core/ControllerConnection.cpp | 10 +- src/core/DataFile.cpp | 5 +- src/core/DrumSynth.cpp | 181 +++++++++++++------------- src/core/EffectChain.cpp | 17 ++- src/core/Engine.cpp | 3 - src/core/EnvelopeAndLfoParameters.cpp | 5 +- src/core/FxMixer.cpp | 1 - src/core/Instrument.cpp | 1 - src/core/JournallingObject.cpp | 3 +- src/core/LfoController.cpp | 29 ++--- src/core/MemoryManager.cpp | 1 + src/core/MixHelpers.cpp | 2 +- src/core/Mixer.cpp | 30 ++--- src/core/MixerWorkerThread.cpp | 14 +- src/core/Note.cpp | 6 +- src/core/NotePlayHandle.cpp | 25 ++-- src/core/PeakController.cpp | 14 +- src/core/base64.cpp | 5 +- src/core/fft_helpers.cpp | 56 ++++---- src/core/main.cpp | 10 +- src/gui/editors/BBEditor.cpp | 4 +- 42 files changed, 281 insertions(+), 329 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 92f7df68e..57c2a6f0f 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -25,7 +25,6 @@ #ifndef AUTOMATABLE_MODEL_H #define AUTOMATABLE_MODEL_H -#include "lmms_math.h" #include #include "JournallingObject.h" @@ -174,7 +173,7 @@ public: { return castValue( m_step ); } - + //! @brief Returns value scaled with the scale type and min/max values of this model float scaledValue( float value ) const; //! @brief Returns value applied with the inverse of this model's scale type @@ -265,22 +264,22 @@ public: } float globalAutomationValueAt( const MidiTime& time ); - + bool hasStrictStepSize() const { return m_hasStrictStepSize; } - + void setStrictStepSize( const bool b ) { m_hasStrictStepSize = b; } - + static void incrementPeriodCounter() { ++s_periodCounter; } - + static void resetPeriodCounter() { s_periodCounter = 0; @@ -333,13 +332,13 @@ private: float m_step; float m_range; float m_centerValue; - + bool m_valueChanged; // currently unused? float m_oldValue; int m_setValueDepth; - + // used to determine if step size should be applied strictly (ie. always) // or only when value set from gui (default) bool m_hasStrictStepSize; @@ -357,9 +356,9 @@ private: ValueBuffer m_valueBuffer; long m_lastUpdatedPeriod; static long s_periodCounter; - + bool m_hasSampleExactData; - + // prevent several threads from attempting to write the same vb at the same time QMutex m_valueBufferMutex; diff --git a/include/BBTrackContainer.h b/include/BBTrackContainer.h index a224495f0..a9e1eb3c2 100644 --- a/include/BBTrackContainer.h +++ b/include/BBTrackContainer.h @@ -27,7 +27,7 @@ #define BB_TRACK_CONTAINER_H #include "TrackContainer.h" -#include "ComboBox.h" +#include "ComboBoxModel.h" class EXPORT BBTrackContainer : public TrackContainer diff --git a/include/BandLimitedWave.h b/include/BandLimitedWave.h index 1c81e0606..d8f1eae13 100644 --- a/include/BandLimitedWave.h +++ b/include/BandLimitedWave.h @@ -26,11 +26,9 @@ #ifndef BANDLIMITEDWAVE_H #define BANDLIMITEDWAVE_H -#include -#include -#include +class QDataStream; +class QString; -#include "ConfigManager.h" #include "export.h" #include "interpolation.h" #include "lmms_basics.h" diff --git a/include/BufferManager.h b/include/BufferManager.h index c2a0a987c..b40b43143 100644 --- a/include/BufferManager.h +++ b/include/BufferManager.h @@ -22,17 +22,14 @@ * Boston, MA 02110-1301 USA. * */ - + #ifndef BUFFER_MANAGER_H #define BUFFER_MANAGER_H -#include "MemoryManager.h" +#include "export.h" #include "lmms_basics.h" -#include "Engine.h" -#include "Mixer.h" -#include -#include +class QAtomicInt; const int BM_INITIAL_BUFFERS = 512; //const int BM_INCREMENT = 64; @@ -45,11 +42,11 @@ public: static void release( sampleFrame * buf ); static void refresh(); // static void extend( int c ); - + private: static sampleFrame ** s_available; static QAtomicInt s_availableIndex; - + static sampleFrame ** s_released; static QAtomicInt s_releasedIndex; // static QReadWriteLock s_mutex; diff --git a/include/ComboBoxModel.h b/include/ComboBoxModel.h index 8c1e64c83..5af4355f0 100644 --- a/include/ComboBoxModel.h +++ b/include/ComboBoxModel.h @@ -29,7 +29,6 @@ #include #include "AutomatableModel.h" -#include "templates.h" class PixmapLoader; diff --git a/include/DataFile.h b/include/DataFile.h index 57db8905f..1d5f71f78 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -28,12 +28,12 @@ #define DATA_FILE_H #include -#include #include "export.h" -#include "lmms_basics.h" #include "MemoryManager.h" +class QTextStream; + class EXPORT DataFile : public QDomDocument { MM_OPERATORS diff --git a/include/DrumSynth.h b/include/DrumSynth.h index e57499038..e29c4bc2c 100644 --- a/include/DrumSynth.h +++ b/include/DrumSynth.h @@ -3,7 +3,7 @@ * * Copyright (c) 1998-2000 Paul Kellett (mda-vst.com) * Copyright (c) 2007 Paul Giblock - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -42,11 +42,11 @@ class DrumSynth { void GetEnv(int env, const char *sec, const char *key, const char *ini); float waveform(float ph, int form); - + int GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file); int GetPrivateProfileInt(const char *sec, const char *key, int def, const char *file); float GetPrivateProfileFloat(const char *sec, const char *key, float def, const char *file); }; -#endif +#endif diff --git a/include/Engine.h b/include/Engine.h index 55dd9021e..ad7abe399 100644 --- a/include/Engine.h +++ b/include/Engine.h @@ -26,28 +26,17 @@ #ifndef ENGINE_H #define ENGINE_H -#include "lmmsconfig.h" -#include "MemoryManager.h" - #include #include "export.h" -class AutomationEditorWindow; -class BBEditor; class BBTrackContainer; class DummyTrackContainer; class FxMixer; -class FxMixerView; class ProjectJournal; -class MainWindow; class Mixer; -class PianoRollWindow; -class ProjectNotes; class Song; -class SongEditorWindow; class Ladspa2LMMS; -class ControllerRackView; class EXPORT Engine diff --git a/include/Instrument.h b/include/Instrument.h index 70831b0ea..fdacce603 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -26,17 +26,18 @@ #ifndef INSTRUMENT_H #define INSTRUMENT_H -#include - +#include +#include +#include "export.h" +#include "lmms_basics.h" +#include "MemoryManager.h" +#include "MidiTime.h" #include "Plugin.h" -#include "Mixer.h" // forward-declarations class InstrumentTrack; -class InstrumentView; class MidiEvent; -class MidiTime; class NotePlayHandle; class Track; diff --git a/include/MemoryManager.h b/include/MemoryManager.h index 44ef58c60..559e90869 100644 --- a/include/MemoryManager.h +++ b/include/MemoryManager.h @@ -28,11 +28,12 @@ #include #include -#include #include #include "MemoryHelper.h" #include "export.h" +class QReadWriteLock; + const int MM_CHUNK_SIZE = 64; // granularity of managed memory const int MM_INITIAL_CHUNKS = 1024 * 1024; // how many chunks to allocate at startup - TODO: make configurable const int MM_INCREMENT_CHUNKS = 16 * 1024; // min. amount of chunks to increment at a time diff --git a/include/MixerWorkerThread.h b/include/MixerWorkerThread.h index 5f5c18c84..e95c13a3b 100644 --- a/include/MixerWorkerThread.h +++ b/include/MixerWorkerThread.h @@ -28,15 +28,9 @@ #include #include -#include "ThreadableJob.h" -#include "Mixer.h" - -#ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include -#endif +class QWaitCondition; +class Mixer; +class ThreadableJob; class MixerWorkerThread : public QThread { diff --git a/include/Model.h b/include/Model.h index 9f0590e25..c62c52ebd 100644 --- a/include/Model.h +++ b/include/Model.h @@ -25,8 +25,8 @@ #ifndef MODEL_H #define MODEL_H +#include #include -#include #include "export.h" diff --git a/include/ModelView.h b/include/ModelView.h index 9e323a947..866546061 100644 --- a/include/ModelView.h +++ b/include/ModelView.h @@ -25,6 +25,7 @@ #ifndef MODEL_VIEW_H #define MODEL_VIEW_H +#include #include "Model.h" diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index d2cf1c0fc..9cabdc346 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -26,14 +26,13 @@ #ifndef NOTE_PLAY_HANDLE_H #define NOTE_PLAY_HANDLE_H -#include "lmmsconfig.h" #include "Note.h" #include "PlayHandle.h" #include "Track.h" #include "MemoryManager.h" -#include -#include +class QAtomicInt; +class QReadWriteLock; class InstrumentTrack; class NotePlayHandle; @@ -59,7 +58,7 @@ public: OriginCount }; typedef Origins Origin; - + NotePlayHandle( InstrumentTrack* instrumentTrack, const f_cnt_t offset, const f_cnt_t frames, @@ -83,9 +82,9 @@ public: { return m_midiChannel; } - + /*! convenience function that returns offset for the first period and zero otherwise, - used by instruments to handle the offset: instruments have to check this property and + used by instruments to handle the offset: instruments have to check this property and add the correct number of empty frames in the beginning of the period */ f_cnt_t noteOffset() const { diff --git a/include/Oscillator.h b/include/Oscillator.h index de7aee66b..e146b5af0 100644 --- a/include/Oscillator.h +++ b/include/Oscillator.h @@ -36,8 +36,6 @@ #include "SampleBuffer.h" #include "lmms_constants.h" - -class SampleBuffer; class IntModel; diff --git a/include/fft_helpers.h b/include/fft_helpers.h index 1fafb6b81..59805c400 100644 --- a/include/fft_helpers.h +++ b/include/fft_helpers.h @@ -26,7 +26,6 @@ #ifndef FFT_HELPERS_H #define FFT_HELPERS_H -#include "lmmsconfig.h" #include "export.h" #include diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 9549f5ad1..6c7501c8b 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -22,9 +22,8 @@ * */ -#include - #include "AutomatableModel.h" + #include "AutomationPattern.h" #include "ControllerConnection.h" #include "lmms_math.h" @@ -75,7 +74,7 @@ AutomatableModel::~AutomatableModel() { delete m_controllerConnection; } - + m_valueBuffer.clear(); emit destroyed( id() ); @@ -171,7 +170,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& //m_controllerConnection->setTargetName( displayName() ); } } - + // models can be stored as elements (port00) or attributes (port10): // // @@ -566,7 +565,7 @@ ValueBuffer * AutomatableModel::valueBuffer() } } AutomatableModel* lm = NULL; - if( m_hasLinkedModels ) + if( m_hasLinkedModels ) { lm = m_linkedModels.first(); } @@ -583,7 +582,7 @@ ValueBuffer * AutomatableModel::valueBuffer() m_hasSampleExactData = true; return &m_valueBuffer; } - + if( m_oldValue != val ) { m_valueBuffer.interpolate( m_oldValue, val ); @@ -592,7 +591,7 @@ ValueBuffer * AutomatableModel::valueBuffer() m_hasSampleExactData = true; return &m_valueBuffer; } - + // if we have no sample-exact source for a ValueBuffer, return NULL to signify that no data is available at the moment // in which case the recipient knows to use the static value() instead m_lastUpdatedPeriod = s_periodCounter; @@ -667,11 +666,11 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) { int s = ( *it )->startPosition(); int e = ( *it )->endPosition(); - if( s <= time && e >= time ) { patternsInRange += ( *it ); } + if( s <= time && e >= time ) { patternsInRange += ( *it ); } } - + AutomationPattern * latestPattern = NULL; - + if( ! patternsInRange.isEmpty() ) { // if there are more than one overlapping patterns, just use the first one because @@ -682,7 +681,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) // if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that { int latestPosition = 0; - + for( QVector::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) { int e = ( *it )->endPosition(); @@ -693,7 +692,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) } } } - + if( latestPattern ) { // scale/fit the value appropriately and return it @@ -701,7 +700,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) const float scaled_value = scaledValue( value ); return fittedValue( scaled_value ); } - // if we still find no pattern, the value at that time is undefined so + // if we still find no pattern, the value at that time is undefined so // just return current value as the best we can do else return m_value; } diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index beb11bd2d..4c8791ee3 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -24,9 +24,8 @@ * */ -#include - #include "AutomationPattern.h" + #include "AutomationPatternView.h" #include "AutomationTrack.h" #include "ProjectJournal.h" @@ -192,7 +191,7 @@ const AutomatableModel * AutomationPattern::firstObject() const MidiTime AutomationPattern::length() const { if( m_timeMap.isEmpty() ) return 0; - timeMap::const_iterator it = m_timeMap.end(); + timeMap::const_iterator it = m_timeMap.end(); return MidiTime( qMax( MidiTime( (it-1).key() ).getTact() + 1, 1 ), 0 ); } @@ -412,7 +411,7 @@ void AutomationPattern::flipY( int min, int max ) { numPoints++; } - + for( int i = 0; i <= numPoints; i++ ) { @@ -501,7 +500,7 @@ void AutomationPattern::flipX( int length ) tempMap[newTime] = tempValue; } } - + m_timeMap.clear(); m_timeMap = tempMap; @@ -617,7 +616,7 @@ void AutomationPattern::processMidiTime( const MidiTime & time ) ( *it )->setAutomatedValue( val ); } - } + } } } else @@ -625,7 +624,7 @@ void AutomationPattern::processMidiTime( const MidiTime & time ) if( time >= 0 && ! m_objects.isEmpty() ) { const float value = static_cast( firstObject()->value() ); - if( value != m_lastRecordedValue ) + if( value != m_lastRecordedValue ) { putValue( time, value, true ); m_lastRecordedValue = value; @@ -692,7 +691,7 @@ QVector AutomationPattern::patternsForModel( const Automata l += Engine::getSong()->tracks(); l += Engine::getBBTrackContainer()->tracks(); l += Engine::getSong()->globalAutomationTrack(); - + // go through all tracks... for( TrackContainer::TrackList::ConstIterator it = l.begin(); it != l.end(); ++it ) { diff --git a/src/core/BBTrackContainer.cpp b/src/core/BBTrackContainer.cpp index 839e40994..d38cfdc00 100644 --- a/src/core/BBTrackContainer.cpp +++ b/src/core/BBTrackContainer.cpp @@ -2,7 +2,7 @@ * BBTrackContainer.cpp - model-component of BB-Editor * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,8 +25,6 @@ #include "BBTrackContainer.h" #include "BBTrack.h" -#include "ComboBox.h" -#include "embed.h" #include "Engine.h" #include "Song.h" diff --git a/src/core/BandLimitedWave.cpp b/src/core/BandLimitedWave.cpp index 11b3790a5..de608ba1d 100644 --- a/src/core/BandLimitedWave.cpp +++ b/src/core/BandLimitedWave.cpp @@ -25,6 +25,7 @@ #include "BandLimitedWave.h" +#include "ConfigManager.h" WaveMipMap BandLimitedWave::s_waveforms[4] = { }; bool BandLimitedWave::s_wavesGenerated = false; @@ -62,7 +63,7 @@ void BandLimitedWave::generateWaves() { // don't generate if they already exist if( s_wavesGenerated ) return; - + int i; // set wavetable directory @@ -90,7 +91,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -115,7 +116,7 @@ void BandLimitedWave::generateWaves() } } } - + // square wave - BLSquare // check for file and use it if exists if( sqr_file.exists() ) @@ -132,7 +133,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -173,7 +174,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -184,7 +185,7 @@ void BandLimitedWave::generateWaves() hlen = static_cast( len ) / static_cast( harm ); const double amp = 1.0 / static_cast( harm * harm ); //const double a2 = cos( om * harm * F_2PI ); - s += amp * /*a2 **/ sin( ( static_cast( ph * harm ) / static_cast( len ) + + s += amp * /*a2 **/ sin( ( static_cast( ph * harm ) / static_cast( len ) + ( ( harm + 1 ) % 4 == 0 ? 0.5 : 0.0 ) ) * F_2PI ); harm += 2; } while( hlen > 2.0 ); @@ -199,7 +200,7 @@ void BandLimitedWave::generateWaves() } } } - + // moog saw wave - BLMoog // basically, just add in triangle + 270-phase saw if( moog_file.exists() ) @@ -214,7 +215,7 @@ void BandLimitedWave::generateWaves() for( i = 0; i <= MAXTBL; i++ ) { const int len = TLENS[i]; - + for( int ph = 0; ph < len; ph++ ) { const int sawph = ( ph + static_cast( len * 0.75 ) ) % len; @@ -224,7 +225,7 @@ void BandLimitedWave::generateWaves() } } } - + // set the generated flag so we don't load/generate them again needlessly s_wavesGenerated = true; @@ -232,14 +233,14 @@ void BandLimitedWave::generateWaves() // generate files, serialize mipmaps as QDataStreams and save them on disk // // normally these are now provided with LMMS as pre-generated so we don't have to do this, -// but I'm leaving the code here in case it's needed in the future +// but I'm leaving the code here in case it's needed in the future // (maybe we add more waveforms or change the generation code or mipmap format, etc.) /* -// if you want to generate the files, you need to set the filenames and paths here - +// if you want to generate the files, you need to set the filenames and paths here - // can't use the usual wavetable directory here as it can require permissions on -// some systems... +// some systems... QFile sawfile( "path-to-wavetables/saw.bin" ); QFile sqrfile( "path-to-wavetables/sqr.bin" ); diff --git a/src/core/BufferManager.cpp b/src/core/BufferManager.cpp index cb38d45e9..1f535443e 100644 --- a/src/core/BufferManager.cpp +++ b/src/core/BufferManager.cpp @@ -25,6 +25,10 @@ #include "BufferManager.h" +#include +#include + +#include "MemoryManager.h" sampleFrame ** BufferManager::s_available; QAtomicInt BufferManager::s_availableIndex = 0; @@ -41,7 +45,7 @@ void BufferManager::init( fpp_t framesPerPeriod ) int c = framesPerPeriod * BM_INITIAL_BUFFERS; sampleFrame * b = MM_ALLOC( sampleFrame, c ); - + for( int i = 0; i < BM_INITIAL_BUFFERS; ++i ) { s_available[ i ] = b; @@ -58,10 +62,10 @@ sampleFrame * BufferManager::acquire() { qFatal( "BufferManager: out of buffers" ); } - + int i = s_availableIndex.fetchAndAddOrdered( -1 ); sampleFrame * b = s_available[ i ]; - + //qDebug( "acquired buffer: %p - index %d", b, i ); return b; } @@ -79,7 +83,7 @@ void BufferManager::refresh() // non-threadsafe, hence it's called periodically { if( s_releasedIndex == 0 ) return; //qDebug( "refresh: %d buffers", int( s_releasedIndex ) ); - + int j = s_availableIndex; for( int i = 0; i < s_releasedIndex; ++i ) { @@ -101,7 +105,7 @@ void BufferManager::extend( int c ) int cc = c * Engine::mixer()->framesPerPeriod(); sampleFrame * b = MM_ALLOC( sampleFrame, cc ); - + for( int i = 0; i < c; ++i ) { s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = b; diff --git a/src/core/ControllerConnection.cpp b/src/core/ControllerConnection.cpp index 3c0266ab6..8b7040b50 100644 --- a/src/core/ControllerConnection.cpp +++ b/src/core/ControllerConnection.cpp @@ -1,5 +1,5 @@ /* - * ControllerConnection.cpp - implementation of class controller connection + * ControllerConnection.cpp - implementation of class controller connection * which handles the link between AutomatableModels and controllers * * Copyright (c) 2008 Paul Giblock @@ -26,12 +26,10 @@ #include #include -#include #include "Song.h" #include "Engine.h" -#include "Mixer.h" #include "ControllerConnection.h" @@ -123,7 +121,7 @@ void ControllerConnection::setController( Controller * _controller ) this, SIGNAL( valueChanged() ) ); } - m_ownsController = + m_ownsController = ( _controller->type() == Controller::MidiController ); // If we don't own the controller, allow deletion of controller @@ -150,8 +148,8 @@ inline void ControllerConnection::setTargetName( const QString & _name ) /* * A connection may not be finalized. This means, the connection should exist, * but the controller does not yet exist. This happens when loading. Even - * loading connections last won't help, since there can be connections BETWEEN - * controllers. So, we remember the controller-ID and use a dummyController + * loading connections last won't help, since there can be connections BETWEEN + * controllers. So, we remember the controller-ID and use a dummyController * instead. Once the song is loaded, finalizeConnections() connects to the proper controllers */ void ControllerConnection::finalizeConnections() diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 7bf47ed67..0cd7a5703 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -42,9 +42,6 @@ #include "lmmsversion.h" #include "base64.h" -// bbTCO::defaultColor() -#include "BBTrack.h" - DataFile::typeDescStruct @@ -628,7 +625,7 @@ void DataFile::upgrade() el.setAttribute( "lp1pos", el.attribute( "lp1pos" ).toInt()*3 ); } - + } if( version < "0.4.0-20080607" ) diff --git a/src/core/DrumSynth.cpp b/src/core/DrumSynth.cpp index 305ed5ae1..8c732bb7d 100644 --- a/src/core/DrumSynth.cpp +++ b/src/core/DrumSynth.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 1998-2000 Paul Kellett (mda-vst.com) * Copyright (c) 2007 Paul Giblock - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,7 +25,6 @@ #include "DrumSynth.h" -#include "lmmsconfig.h" #include #include @@ -71,13 +70,13 @@ float mem_t=1.0f, mem_o=1.0f, mem_n=1.0f, mem_b=1.0f, mem_tune=1.0f, mem_time=1. int DrumSynth::LongestEnv(void) { long e, eon, p; - float l=0.f; - + float l=0.f; + for(e=1; e<7; e++) //3 { eon = e - 1; if(eon>2) eon=eon-1; p = 0; - while (envpts[e][0][p + 1] >= 0.f) p++; + while (envpts[e][0][p + 1] >= 0.f) p++; envData[e][MAX] = envpts[e][0][p] * timestretch; if(chkOn[eon]==1) if(envData[e][MAX]>l) l=envData[e][MAX]; } @@ -88,7 +87,7 @@ int DrumSynth::LongestEnv(void) float DrumSynth::LoudestEnv(void) -{ +{ float loudest=0.f; int i=0; @@ -102,9 +101,9 @@ float DrumSynth::LoudestEnv(void) void DrumSynth::UpdateEnv(int e, long t) -{ +{ float endEnv, dT; - //0.2's added + //0.2's added envData[e][NEXTT] = envpts[e][0][(long)(envData[e][PNT] + 1.f)] * timestretch; //get next point if(envData[e][NEXTT] < 0) envData[e][NEXTT] = 442000 * timestretch; //if end point, hold envData[e][ENV] = envpts[e][1][(long)(envData[e][PNT] + 0.f)] * 0.01f; //this level @@ -122,14 +121,14 @@ void DrumSynth::GetEnv(int env, const char *sec, const char *key, const char *in int i=0, o=0, ep=0; GetPrivateProfileString(sec, key, "0,0 100,0", en, sizeof(en), ini); en[255]=0; //be safe! - + while(en[i]!=0) { - if(en[i] == ',') + if(en[i] == ',') { if(sscanf(s, "%f", &envpts[env][0][ep])==0) envpts[env][0][ep] = 0.f; o=0; - } + } else if(en[i] == ' ') { if(sscanf(s, "%f", &envpts[env][1][ep])==0) envpts[env][1][ep] = 0.f; @@ -148,7 +147,7 @@ void DrumSynth::GetEnv(int env, const char *sec, const char *key, const char *in float DrumSynth::waveform(float ph, int form) { float w; - + switch (form) { case 0: w = (float)sin(fmod(ph,TwoPi)); break; //sine @@ -157,15 +156,15 @@ float DrumSynth::waveform(float ph, int form) w = 0.6366197f * (float)fmod(ph,TwoPi) - 1.f; //tri if(w>1.f) w=2.f-w; break; case 3: w = ph - TwoPi * (float)(int)(ph / TwoPi); //saw - w = (0.3183098f * w) - 1.f; break; + w = (0.3183098f * w) - 1.f; break; default: w = (sin(fmod(ph,TwoPi))>0.0)? 1.f: -1.f; break; //square - } - + } + return w; } -int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file) +int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file) { ifstream is; bool inSection = false; @@ -190,12 +189,12 @@ int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const c } else if (!is.eof()) { is.getline(line, 200); - if (line[0] == '[') + if (line[0] == '[') break; k = strtok(line, " \t="); b = strtok(NULL, "\n\r\0"); - + if (k != 0 && strcasecmp(k, key)==0) { if (b==0) { len = 0; @@ -203,7 +202,7 @@ int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const c } else { k = (char *)(b + strlen(b)-1); - while ( (k>=b) && (*k==' ' || *k=='\t') ) + while ( (k>=b) && (*k==' ' || *k=='\t') ) --k; *(k+1) = '\0'; @@ -233,9 +232,9 @@ int DrumSynth::GetPrivateProfileInt(const char *sec, const char *key, int def, c int i=0; GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file); - sscanf(tmp, "%d", &i); if(tmp[0]==0) i=def; - - return i; + sscanf(tmp, "%d", &i); if(tmp[0]==0) i=def; + + return i; } float DrumSynth::GetPrivateProfileFloat(const char *sec, const char *key, float def, const char *file) @@ -244,9 +243,9 @@ float DrumSynth::GetPrivateProfileFloat(const char *sec, const char *key, float float f=0.f; GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file); - sscanf(tmp, "%f", &f); if(tmp[0]==0) f=def; + sscanf(tmp, "%f", &f); if(tmp[0]==0) f=def; - return f; + return f; } @@ -259,7 +258,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { //input file char sec[32]; - char ver[32]; + char ver[32]; char comment[256]; int commentLen=0; @@ -268,11 +267,11 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels float x[3] = {0.f, 0.f, 0.f}; float MasterTune, randmax, randmax2; int MainFilter, HighPass; - + long NON, NT, TON, DiON, TDroop=0, DStep; float a, b=0.f, c=0.f, d=0.f, g, TT=0.f, TL, NL, F1, F2; float TphiStart=0.f, Tphi, TDroopRate, ddF, DAtten, DGain; - + long BON, BON2, BFStep, BFStep2, botmp; float BdF=0.f, BdF2=0.f, BPhi, BPhi2, BF, BF2, BQ, BQ2, BL, BL2; @@ -282,7 +281,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels float Oc0=0.0f, Oc1=0.0f, Oc2=0.0f; float MFfb, MFtmp, MFres, MFin=0.f, MFout=0.f; - float DownAve; + float DownAve; long DownStart, DownEnd, jj; @@ -297,22 +296,22 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels } //try to read version from input file - strcpy(sec, "General"); + strcpy(sec, "General"); GetPrivateProfileString(sec,"Version","",ver,sizeof(ver),dsfile); - ver[9]=0; + ver[9]=0; if(strcasecmp(ver, "DrumSynth") != 0) {return 0;} //input fail if(ver[11] != '1' && ver[11] != '2') {return 0;} //version fail - + //read master parameters GetPrivateProfileString(sec,"Comment","",comment,sizeof(comment),dsfile); while((comment[commentLen]!=0) && (commentLen<254)) commentLen++; if(commentLen==0) { comment[0]=32; comment[1]=0; commentLen=1;} comment[commentLen+1]=0; commentLen++; - if((commentLen % 2)==1) commentLen++; - + if((commentLen % 2)==1) commentLen++; + timestretch = .01f * mem_time * GetPrivateProfileFloat(sec,"Stretch",100.0,dsfile); - if(timestretch<0.2f) timestretch=0.2f; + if(timestretch<0.2f) timestretch=0.2f; if(timestretch>10.f) timestretch=10.f; DGain = 1.0f; //leave this here! @@ -320,35 +319,35 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels MasterTune = GetPrivateProfileFloat(sec,"Tuning",0.0,dsfile); MasterTune = (float)powf(1.0594631f, MasterTune + mem_tune); - MainFilter = 2 * GetPrivateProfileInt(sec,"Filter",0,dsfile); + MainFilter = 2 * GetPrivateProfileInt(sec,"Filter",0,dsfile); MFres = 0.0101f * GetPrivateProfileFloat(sec,"Resonance",0.0,dsfile); MFres = (float)powf(MFres, 0.5f); - + HighPass = GetPrivateProfileInt(sec,"HighPass",0,dsfile); GetEnv(7, sec, "FilterEnv", dsfile); - + //read noise parameters strcpy(sec, "Noise"); chkOn[1] = GetPrivateProfileInt(sec,"On",0,dsfile); - sliLev[1] = GetPrivateProfileInt(sec,"Level",0,dsfile); - NT = GetPrivateProfileInt(sec,"Slope",0,dsfile); + sliLev[1] = GetPrivateProfileInt(sec,"Level",0,dsfile); + NT = GetPrivateProfileInt(sec,"Slope",0,dsfile); GetEnv(2, sec, "Envelope", dsfile); - NON = chkOn[1]; + NON = chkOn[1]; NL = (float)(sliLev[1] * sliLev[1]) * mem_n; if(NT<0) { a = 1.f + (NT / 105.f); d = -NT / 105.f; g = (1.f + 0.0005f * NT * NT) * NL; } else { a = 1.f; b = -NT / 50.f; c = (float)fabs((float)NT) / 100.f; g = NL; } - - //if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0) + + //if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0) //srand(1); //fixed random sequence - + //read tone parameters strcpy(sec, "Tone"); chkOn[0] = GetPrivateProfileInt(sec,"On",0,dsfile); TON = chkOn[0]; - sliLev[0] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[0] = GetPrivateProfileInt(sec,"Level",128,dsfile); TL = (float)(sliLev[0] * sliLev[0]) * mem_t; GetEnv(1, sec, "Envelope", dsfile); F1 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F1",200.0,dsfile) / Fs; @@ -364,13 +363,13 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels ddF = F1 - F2; } else ddF = F2-F1; - + Tphi = GetPrivateProfileFloat(sec,"Phase",90.f,dsfile) / 57.29578f; //degrees>radians //read overtone parameters strcpy(sec, "Overtones"); chkOn[2] = GetPrivateProfileInt(sec,"On",0,dsfile); OON = chkOn[2]; - sliLev[2] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[2] = GetPrivateProfileInt(sec,"Level",128,dsfile); OL = (float)(sliLev[2] * sliLev[2]) * mem_o; GetEnv(3, sec, "Envelope1", dsfile); GetEnv(4, sec, "Envelope2", dsfile); @@ -381,11 +380,11 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels OW2 = GetPrivateProfileInt(sec,"Wave2",0,dsfile); OBal2 = (float)GetPrivateProfileInt(sec,"Param",50,dsfile); ODrive = (float)powf(OBal2, 3.0f) / (float)powf(50.0f, 3.0f); - OBal2 *= 0.01f; + OBal2 *= 0.01f; OBal1 = 1.f - OBal2; - Ophi1 = Tphi; + Ophi1 = Tphi; Ophi2 = Tphi; - if(MainFilter==0) + if(MainFilter==0) MainFilter = GetPrivateProfileInt(sec,"Filter",0,dsfile); if((GetPrivateProfileInt(sec,"Track1",0,dsfile)==1) && (TON==1)) { OF1Sync = 1; OF1 = OF1 / F1; } @@ -403,28 +402,28 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels //read noise band parameters strcpy(sec, "NoiseBand"); chkOn[3] = GetPrivateProfileInt(sec,"On",0,dsfile); BON = chkOn[3]; - sliLev[3] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[3] = GetPrivateProfileInt(sec,"Level",128,dsfile); BL = (float)(sliLev[3] * sliLev[3]) * mem_b; BF = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs; BPhi = TwoPi / 8.f; GetEnv(5, sec, "Envelope", dsfile); - BFStep = GetPrivateProfileInt(sec,"dF",50,dsfile); - BQ = (float)BFStep; + BFStep = GetPrivateProfileInt(sec,"dF",50,dsfile); + BQ = (float)BFStep; BQ = BQ * BQ / (10000.f-6600.f*((float)sqrt(BF)-0.19f)); BFStep = 1 + (int)((40.f - (BFStep / 2.5f)) / (BQ + 1.f + (1.f * BF))); strcpy(sec, "NoiseBand2"); chkOn[4] = GetPrivateProfileInt(sec,"On",0,dsfile); BON2 = chkOn[4]; - sliLev[4] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[4] = GetPrivateProfileInt(sec,"Level",128,dsfile); BL2 = (float)(sliLev[4] * sliLev[4]) * mem_b; BF2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs; BPhi2 = TwoPi / 8.f; GetEnv(6, sec, "Envelope", dsfile); - BFStep2 = GetPrivateProfileInt(sec,"dF",50,dsfile); + BFStep2 = GetPrivateProfileInt(sec,"dF",50,dsfile); BQ2 = (float)BFStep2; BQ2 = BQ2 * BQ2 / (10000.f-6600.f*((float)sqrt(BF2)-0.19f)); BFStep2 = 1 + (int)((40 - (BFStep2 / 2.5)) / (BQ2 + 1 + (1 * BF2))); - + //read distortion parameters strcpy(sec, "Distortion"); chkOn[5] = GetPrivateProfileInt(sec,"On",0,dsfile); DiON = chkOn[5]; @@ -434,14 +433,14 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels clippoint = 32700; DAtten = 1.0f; - if(DiON==1) + if(DiON==1) { - DAtten = DGain * (short)LoudestEnv(); - if(DAtten>32700) clippoint=32700; else clippoint=(short)DAtten; + DAtten = DGain * (short)LoudestEnv(); + if(DAtten>32700) clippoint=32700; else clippoint=(short)DAtten; DAtten = (float)powf(2.0, 2.0 * GetPrivateProfileInt(sec,"Bits",0,dsfile)); DGain = DAtten * DGain * (float)powf(10.0, 0.05 * GetPrivateProfileInt(sec,"Clipping",0,dsfile)); } - + //prepare envelopes randmax = 1.f / RAND_MAX; randmax2 = 2.f * randmax; for (i=1;i<8;i++) { envData[i][NEXTT]=0; envData[i][PNT]=0; } @@ -473,7 +472,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels //write WAV header WH.riff = 0x46464952; - WH.riffLength = 36 + (2 * Length) + 44 + commentLen; + WH.riffLength = 36 + (2 * Length) + 44 + commentLen; WH.wave = 0x45564157; WH.fmt = 0x20746D66; WH.waveLength = 16; @@ -503,7 +502,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels else UpdateEnv(2, t); x[2] = x[1]; x[1] = x[0]; - x[0] = (randmax2 * (float)rand()) - 1.f; + x[0] = (randmax2 * (float)rand()) - 1.f; TT = a * x[0] + b * x[1] + c * x[2] + d * TT; DF[t - tpos] = TT * g * envData[2][ENV]; } @@ -512,7 +511,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels else { for(j=0; j<1200; j++) DF[j]=0.f; } - + if(TON==1) //tone { TphiStart = Tphi; @@ -520,16 +519,16 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { for(t=tpos; t<=tplus; t++) phi[t - tpos] = F2 + (ddF * (float)exp(t * TDroopRate)); - } + } else { for(t=tpos; t<=tplus; t++) phi[t - tpos] = F1 + (t / envData[1][MAX]) * ddF; - } + } for(t=tpos; t<=tplus; t++) { totmp = t - tpos; - if(t < envData[1][NEXTT]) + if(t < envData[1][NEXTT]) envData[1][ENV] = envData[1][ENV] + envData[1][dENV]; else UpdateEnv(1, t); Tphi = Tphi + phi[totmp]; @@ -538,7 +537,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels if(t>=envData[1][MAX]) TON=0; } else for(j=0; j<1200; j++) phi[j]=F2; //for overtone sync - + if(BON==1) //noise band 1 { for(t=tpos; t<=tplus; t++) @@ -580,8 +579,8 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { if(t>=envData[3][MAX]) //wait for OT2 { - envData[3][ENV] = 0; - envData[3][dENV] = 0; + envData[3][ENV] = 0; + envData[3][dENV] = 0; envData[3][NEXTT] = 999999; } else UpdateEnv(3, t); @@ -610,12 +609,12 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels Ot = OBal1 * envData[3][ENV] * waveform(Ophi1, OW1); Ot = OL * (Ot + OBal2 * envData[4][ENV] * waveform(Ophi2, OW2)); break; - + case 1: //FM Ot = ODrive * envData[4][ENV] * waveform(Ophi2, OW2); Ot = OL * envData[3][ENV] * waveform(Ophi1 + Ot, OW1); break; - + case 2: //RM Ot = (1 - ODrive / 8) + (((ODrive / 8) * envData[4][ENV]) * waveform(Ophi2, OW2)); Ot = OL * envData[3][ENV] * waveform(Ophi1, OW1) * Ot; @@ -625,10 +624,10 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels for(j=0; j<6; j++) { Oc[j][0] += 1.0f; - + if(Oc[j][0]>Oc[j][1]) - { - Oc[j][0] -= Oc[j][1]; + { + Oc[j][0] -= Oc[j][1]; Ot = OL * envData[3][ENV]; } } @@ -639,8 +638,8 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels Ot = Oc1; break; } - } - + } + if(MainFilter==1) //filter overtones { if(t0.2f) MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1); else - MFfb = 0.999f - 0.7824f * MFtmp; - - MFtmp = Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); + MFfb = 0.999f - 0.7824f * MFtmp; + + MFtmp = Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); MFin = MFfb * (MFin - MFtmp) + MFtmp; MFout = MFfb * (MFout - MFin) + MFin; @@ -669,48 +668,48 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels if(MFtmp >0.2f) MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1); else - MFfb = 0.999f - 0.7824f * MFtmp; - - MFtmp = DF[t - tpos] + Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); + MFfb = 0.999f - 0.7824f * MFtmp; + + MFtmp = DF[t - tpos] + Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); MFin = MFfb * (MFin - MFtmp) + MFtmp; MFout = MFfb * (MFout - MFin) + MFin; - + DF[t - tpos] = MFout - (HighPass * (DF[t - tpos] + Ot)); } // PG: Ot is uninitialized else DF[t - tpos] = DF[t - tpos] + Ot; //no filter } - + if(DiON==1) //bit resolution { for(j=0; j<1200; j++) DF[j] = DGain * (int)(DF[j] / DAtten); - + for(j=0; j<1200; j+=DStep) //downsampling { DownAve = 0; DownStart = j; DownEnd = j + DStep - 1; - for(jj = DownStart; jj<=DownEnd; jj++) + for(jj = DownStart; jj<=DownEnd; jj++) DownAve = DownAve + DF[jj]; DownAve = DownAve / DStep; - for(jj = DownStart; jj<=DownEnd; jj++) + for(jj = DownStart; jj<=DownEnd; jj++) DF[jj] = DownAve; - } + } } else for(j=0; j<1200; j++) DF[j] *= DGain; - + for(j = 0; j<1200; j++) //clipping + output { if(DF[j] > clippoint) wave[wavewords++] = clippoint; - else if(DF[j] < -clippoint) + else if(DF[j] < -clippoint) wave[wavewords++] = -clippoint; - else + else wave[wavewords++] = (short)DF[j]; for (int c = 1; c < channels; c++) { - wave[wavewords] = wave[wavewords-1]; + wave[wavewords] = wave[wavewords-1]; wavewords++; } } diff --git a/src/core/EffectChain.cpp b/src/core/EffectChain.cpp index 5890566a3..f310f94dc 100644 --- a/src/core/EffectChain.cpp +++ b/src/core/EffectChain.cpp @@ -29,7 +29,6 @@ #include "EffectChain.h" #include "Effect.h" #include "Engine.h" -#include "debug.h" #include "DummyEffect.h" #include "MixHelpers.h" #include "Song.h" @@ -148,7 +147,7 @@ void EffectChain::moveDown( Effect * _effect ) if( _effect != m_effects.last() ) { int i = 0; - for( EffectList::Iterator it = m_effects.begin(); + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) { if( *it == _effect ) @@ -156,10 +155,10 @@ void EffectChain::moveDown( Effect * _effect ) break; } } - + Effect * temp = m_effects[i + 1]; m_effects[i + 1] = _effect; - m_effects[i] = temp; + m_effects[i] = temp; } } @@ -171,7 +170,7 @@ void EffectChain::moveUp( Effect * _effect ) if( _effect != m_effects.first() ) { int i = 0; - for( EffectList::Iterator it = m_effects.begin(); + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) { if( *it == _effect ) @@ -179,10 +178,10 @@ void EffectChain::moveUp( Effect * _effect ) break; } } - + Effect * temp = m_effects[i - 1]; m_effects[i - 1] = _effect; - m_effects[i] = temp; + m_effects[i] = temp; } } @@ -240,8 +239,8 @@ void EffectChain::startRunning() { return; } - - for( EffectList::Iterator it = m_effects.begin(); + + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++ ) { ( *it )->startRunning(); diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp index b11ad1e47..5730e977e 100644 --- a/src/core/Engine.cpp +++ b/src/core/Engine.cpp @@ -27,13 +27,10 @@ #include "BBTrackContainer.h" #include "ConfigManager.h" #include "FxMixer.h" -#include "InstrumentTrack.h" #include "Ladspa2LMMS.h" #include "Mixer.h" -#include "Pattern.h" #include "PresetPreviewPlayHandle.h" #include "ProjectJournal.h" -#include "ProjectNotes.h" #include "Plugin.h" #include "Song.h" #include "BandLimitedWave.h" diff --git a/src/core/EnvelopeAndLfoParameters.cpp b/src/core/EnvelopeAndLfoParameters.cpp index 90f6747f0..271bfd6f4 100644 --- a/src/core/EnvelopeAndLfoParameters.cpp +++ b/src/core/EnvelopeAndLfoParameters.cpp @@ -25,7 +25,6 @@ #include #include "EnvelopeAndLfoParameters.h" -#include "debug.h" #include "Engine.h" #include "Mixer.h" #include "Oscillator.h" @@ -379,7 +378,7 @@ void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this ) with 4.15 file format*/ if( _this.hasAttribute( "sus" ) ) - { + { m_sustainModel.loadSettings( _this, "sus" ); m_sustainModel.setValue( 1.0 - m_sustainModel.value() ); } @@ -392,7 +391,7 @@ void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this ) ( TempoSyncKnob::TtempoSyncMode ) _this.attribute( "lfosyncmode" ).toInt() ); }*/ - + m_userWave.setAudioFile( _this.attribute( "userwavefile" ) ); updateSampleVars(); diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index e6d1767ff..00143b2ee 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -27,7 +27,6 @@ #include "FxMixer.h" #include "MixerWorkerThread.h" #include "MixHelpers.h" -#include "Effect.h" #include "Song.h" #include "InstrumentTrack.h" diff --git a/src/core/Instrument.cpp b/src/core/Instrument.cpp index f8b04fdb5..b4bf40bd1 100644 --- a/src/core/Instrument.cpp +++ b/src/core/Instrument.cpp @@ -26,7 +26,6 @@ #include "InstrumentTrack.h" #include "DummyInstrument.h" #include "NotePlayHandle.h" -#include "embed.h" #include "Engine.h" diff --git a/src/core/JournallingObject.cpp b/src/core/JournallingObject.cpp index 804483580..4c3163f0c 100644 --- a/src/core/JournallingObject.cpp +++ b/src/core/JournallingObject.cpp @@ -29,7 +29,6 @@ #include "JournallingObject.h" #include "AutomatableModel.h" #include "ProjectJournal.h" -#include "base64.h" #include "Engine.h" @@ -70,7 +69,7 @@ void JournallingObject::addJournalCheckPoint() QDomElement JournallingObject::saveState( QDomDocument & _doc, QDomElement & _parent ) { - if( isJournalling() ) + if( isJournalling() ) { QDomElement _this = SerializingObject::saveState( _doc, _parent ); diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index 5d77ce06a..f7c65a752 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -23,17 +23,14 @@ * */ -#include #include #include -#include #include "Song.h" #include "Engine.h" #include "Mixer.h" #include "LfoController.h" -#include "ControllerDialog.h" #include "lmms_math.h" @@ -47,7 +44,7 @@ LfoController::LfoController( Model * _parent ) : this, tr( "Oscillator waveform" ) ), m_multiplierModel( 0, 0, 2, this, tr( "Frequency Multiplier" ) ), m_duration( 1000 ), - m_phaseOffset( 0 ), + m_phaseOffset( 0 ), m_currentPhase( 0 ), m_sampleFunction( &Oscillator::sinSample ), m_userDefSampleBuffer( new SampleBuffer ) @@ -55,19 +52,19 @@ LfoController::LfoController( Model * _parent ) : setSampleExact( true ); connect( &m_waveModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleFunction() ) ); - + connect( &m_speedModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); connect( &m_multiplierModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), + connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateDuration() ) ); - + connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( updatePhase() ) ); connect( Engine::getSong(), SIGNAL( playbackPositionChanged() ), this, SLOT( updatePhase() ) ); - + updateDuration(); } @@ -88,12 +85,12 @@ LfoController::~LfoController() void LfoController::updateValueBuffer() { - m_phaseOffset = m_phaseModel.value() / 360.0; - float * values = m_valueBuffer.values(); + m_phaseOffset = m_phaseModel.value() / 360.0; + float * values = m_valueBuffer.values(); float phase = m_currentPhase + m_phaseOffset; // roll phase up until we're in sync with period counter - m_bufferLastUpdated++; + m_bufferLastUpdated++; if( m_bufferLastUpdated < s_periods ) { int diff = s_periods - m_bufferLastUpdated; @@ -103,16 +100,16 @@ void LfoController::updateValueBuffer() for( int i = 0; i < m_valueBuffer.length(); i++ ) - { - const float currentSample = m_sampleFunction != NULL + { + const float currentSample = m_sampleFunction != NULL ? m_sampleFunction( phase ) : m_userDefSampleBuffer->userWaveSample( phase ); - + values[i] = qBound( 0.0f, m_baseModel.value() + ( m_amountModel.value() * currentSample / 2.0f ), 1.0f ); phase += 1.0 / m_duration; } - + m_currentPhase = absFraction( phase - m_phaseOffset ); } @@ -141,7 +138,7 @@ void LfoController::updateDuration() default: break; } - + m_duration = newDurationF; } diff --git a/src/core/MemoryManager.cpp b/src/core/MemoryManager.cpp index 21cdf01ba..7366aa234 100644 --- a/src/core/MemoryManager.cpp +++ b/src/core/MemoryManager.cpp @@ -26,6 +26,7 @@ #include "MemoryManager.h" #include +#include #include diff --git a/src/core/MixHelpers.cpp b/src/core/MixHelpers.cpp index 513dd40d9..22065c967 100644 --- a/src/core/MixHelpers.cpp +++ b/src/core/MixHelpers.cpp @@ -22,8 +22,8 @@ * */ -#include "lmms_math.h" #include "MixHelpers.h" +#include "lmms_math.h" #include "ValueBuffer.h" diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index b6aff0446..ba8006ddd 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -22,18 +22,14 @@ * */ -#include - #include "Mixer.h" + +#include "AudioPort.h" #include "FxMixer.h" -#include "MixHelpers.h" #include "MixerWorkerThread.h" #include "Song.h" -#include "templates.h" #include "EnvelopeAndLfoParameters.h" #include "NotePlayHandle.h" -#include "InstrumentTrack.h" -#include "debug.h" #include "Engine.h" #include "ConfigManager.h" #include "SamplePlayHandle.h" @@ -292,7 +288,7 @@ void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) f_cnt_t frames = m_inputBufferFrames[ m_inputBufferWrite ]; int size = m_inputBufferSize[ m_inputBufferWrite ]; sampleFrame * buf = m_inputBuffer[ m_inputBufferWrite ]; - + if( frames + _frames > size ) { size = qMax( size * 2, frames + _frames ); @@ -305,10 +301,10 @@ void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) buf = ab; } - + memcpy( &buf[ frames ], _ab, _frames * sizeof( sampleFrame ) ); m_inputBufferFrames[ m_inputBufferWrite ] += _frames; - + unlockInputFrames(); } @@ -359,7 +355,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() if( it != m_playHandles.end() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -415,7 +411,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() if( ( *it )->isFinished() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -446,7 +442,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() EnvelopeAndLfoParameters::instances()->trigger(); Controller::triggerFrameCounter(); AutomatableModel::incrementPeriodCounter(); - + // refresh buffer pool BufferManager::refresh(); @@ -639,7 +635,7 @@ bool Mixer::addPlayHandle( PlayHandle* handle ) return true; } - if( handle->type() == PlayHandle::TypeNotePlayHandle ) + if( handle->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*)handle ); } @@ -664,7 +660,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) if( it != m_playHandles.end() ) { m_playHandles.erase( it ); - if( _ph->type() == PlayHandle::TypeNotePlayHandle ) + if( _ph->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) _ph ); } @@ -690,7 +686,7 @@ void Mixer::removePlayHandles( Track * _track, bool removeIPHs ) if( ( *it )->isFromTrack( _track ) && ( removeIPHs || ( *it )->type() != PlayHandle::TypeInstrumentPlayHandle ) ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -942,8 +938,8 @@ void Mixer::fifoWriter::run() #ifdef __SSE__ /* FTZ flag */ _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif - +#endif + #if 0 #ifdef LMMS_BUILD_LINUX #ifdef LMMS_HAVE_SCHED_H diff --git a/src/core/MixerWorkerThread.cpp b/src/core/MixerWorkerThread.cpp index 5a9ca166c..ef011f55f 100644 --- a/src/core/MixerWorkerThread.cpp +++ b/src/core/MixerWorkerThread.cpp @@ -23,8 +23,18 @@ */ #include "MixerWorkerThread.h" -#include "Engine.h" +#include +#include +#include "ThreadableJob.h" +#include "Mixer.h" + +#ifdef __SSE__ +#include +#endif +#ifdef __SSE3__ +#include +#endif MixerWorkerThread::JobQueue MixerWorkerThread::globalJobQueue; QWaitCondition * MixerWorkerThread::queueReadyWaitCond = NULL; @@ -157,7 +167,7 @@ void MixerWorkerThread::run() #ifdef __SSE__ /* FTZ flag */ _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif +#endif QMutex m; while( m_quit == false ) { diff --git a/src/core/Note.cpp b/src/core/Note.cpp index 937f52ac8..fb76a491c 100644 --- a/src/core/Note.cpp +++ b/src/core/Note.cpp @@ -2,7 +2,7 @@ * note.cpp - implementation of class note * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -29,8 +29,6 @@ #include "Note.h" #include "DetuningHelper.h" -#include "templates.h" - @@ -68,7 +66,7 @@ Note::Note( const Note & _note ) : m_selected( _note.m_selected ), m_oldKey( _note.m_oldKey ), m_oldPos( _note.m_oldPos ), - m_oldLength( _note.m_oldLength ), + m_oldLength( _note.m_oldLength ), m_isPlaying( _note.m_isPlaying ), m_key( _note.m_key), m_volume( _note.m_volume ), diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 19ec0517a..be5a38295 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -25,7 +25,6 @@ #include "NotePlayHandle.h" #include "BasicFilters.h" -#include "ConfigManager.h" #include "DetuningHelper.h" #include "InstrumentSoundShaping.h" #include "InstrumentTrack.h" @@ -93,14 +92,14 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, parent->m_hadChildren = true; m_bbTrack = parent->m_bbTrack; - + parent->setUsesBuffer( false ); } updateFrequency(); setFrames( _frames ); - + // inform attached components about new MIDI note (used for recording in Piano Roll) if( m_origin == OriginMidiInput ) { @@ -114,7 +113,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, // send MidiNoteOn event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ), - MidiTime::fromFrames( offset(), Engine::framesPerTick() ), + MidiTime::fromFrames( offset(), Engine::framesPerTick() ), offset() ); } @@ -122,9 +121,9 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, { setUsesBuffer( false ); } - + setAudioPort( instrumentTrack->audioPort() ); - + unlock(); } @@ -133,7 +132,7 @@ void NotePlayHandle::done() { lock(); noteOff( 0 ); - + if( hasParent() == false ) { delete m_baseDetuning; @@ -157,7 +156,7 @@ void NotePlayHandle::done() m_subNotes.clear(); delete m_filter; - + if( buffer() ) releaseBuffer(); unlock(); @@ -212,7 +211,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) setOffset( offset() - Engine::mixer()->framesPerPeriod() ); return; } - + lock(); if( m_frequencyNeedsUpdate ) { @@ -220,7 +219,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) } // number of frames that can be played this period - f_cnt_t framesThisPeriod = m_totalFramesPlayed == 0 + f_cnt_t framesThisPeriod = m_totalFramesPlayed == 0 ? Engine::mixer()->framesPerPeriod() - offset() : Engine::mixer()->framesPerPeriod(); @@ -386,7 +385,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) // send MidiNoteOff event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ), - MidiTime::fromFrames( _s, Engine::framesPerTick() ), + MidiTime::fromFrames( _s, Engine::framesPerTick() ), _s ); } @@ -597,7 +596,7 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac s_mutex.lockForRead(); NotePlayHandle * nph = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ]; s_mutex.unlock(); - + new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin ); return nph; } @@ -618,7 +617,7 @@ void NotePlayHandleManager::extend( int c ) NotePlayHandle ** tmp = MM_ALLOC( NotePlayHandle*, s_size ); MM_FREE( s_available ); s_available = tmp; - + NotePlayHandle * n = MM_ALLOC( NotePlayHandle, c ); for( int i=0; i < c; ++i ) diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index c8702f937..2d92cff05 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -23,24 +23,20 @@ * */ +#include "PeakController.h" + #include #include #include -#include #include - -#include "Song.h" #include "Engine.h" #include "Mixer.h" -#include "PeakController.h" #include "EffectChain.h" -#include "ControllerDialog.h" #include "plugins/peak_controller_effect/peak_controller_effect.h" #include "PresetPreviewPlayHandle.h" -#include "lmms_math.h" -#include "interpolation.h" +class ControllerDialog; PeakControllerEffectVector PeakController::s_effects; int PeakController::m_getCount; @@ -48,7 +44,7 @@ int PeakController::m_loadCount; bool PeakController::m_buggedFile; -PeakController::PeakController( Model * _parent, +PeakController::PeakController( Model * _parent, PeakControllerEffect * _peak_effect ) : Controller( Controller::PeakController, _parent, tr( "Peak Controller" ) ), m_peakEffect( _peak_effect ), @@ -99,7 +95,7 @@ void PeakController::updateValueBuffer() { const f_cnt_t frames = Engine::mixer()->framesPerPeriod(); float * values = m_valueBuffer.values(); - + for( f_cnt_t f = 0; f < frames; ++f ) { const float diff = ( targetSample - m_currentSample ); diff --git a/src/core/base64.cpp b/src/core/base64.cpp index 08adc9d46..0479d468b 100644 --- a/src/core/base64.cpp +++ b/src/core/base64.cpp @@ -3,7 +3,7 @@ * to/from base64 * * Copyright (c) 2006-2008 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -26,7 +26,6 @@ #include "base64.h" -#include "lmms_basics.h" #include #include @@ -34,7 +33,7 @@ namespace base64 { - + QString encode( const QVariant & _data ) { QBuffer buf; diff --git a/src/core/fft_helpers.cpp b/src/core/fft_helpers.cpp index 71e84a8db..11f619c4a 100644 --- a/src/core/fft_helpers.cpp +++ b/src/core/fft_helpers.cpp @@ -2,7 +2,7 @@ * fft_helpers.cpp - some functions around FFT analysis * * Copyright (c) 2008-2012 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,8 +25,8 @@ #include "fft_helpers.h" -#include "lmms_math.h" - +#include +#include "lmms_constants.h" /* returns biggest value from abs_spectrum[spec_size] array @@ -36,10 +36,10 @@ float maximum(float *abs_spectrum, unsigned int spec_size) { float maxi=0; unsigned int i; - + if ( abs_spectrum==NULL ) return -1; - + if (spec_size<=0) return -1; @@ -48,7 +48,7 @@ float maximum(float *abs_spectrum, unsigned int spec_size) if ( abs_spectrum[i]>maxi ) maxi=abs_spectrum[i]; } - + return maxi; } @@ -60,21 +60,21 @@ int hanming(float *timebuffer, int length, WINDOWS type) { int i; float alpha; - + if ( (timebuffer==NULL)||(length<=0) ) return -1; - + switch (type) { case HAMMING: alpha=0.54; break; - case HANNING: + case HANNING: default: alpha=0.5; break; } - + for ( i=0; i num_new - + returns 0 on success, else -1 */ int compressbands(float *absspec_buffer, float *compressedband, int num_old, int num_new, int bottom, int top) { @@ -114,13 +114,13 @@ int compressbands(float *absspec_buffer, float *compressedband, int num_old, int int i, usefromold; float j; float j_min, j_max; - + if ( (absspec_buffer==NULL)||(compressedband==NULL) ) return -1; - + if ( num_old #endif -#include #include #include -#include #include #include #include -#include -#include #include -#include -#include +#include #ifdef LMMS_BUILD_WIN32 #include @@ -71,16 +66,13 @@ #include "MemoryManager.h" #include "ConfigManager.h" #include "NotePlayHandle.h" -#include "embed.h" #include "Engine.h" #include "GuiApplication.h" -#include "LmmsStyle.h" #include "ImportFilter.h" #include "MainWindow.h" #include "ProjectRenderer.h" #include "DataFile.h" #include "Song.h" -#include "LmmsPalette.h" static inline QString baseName( const QString & _file ) { diff --git a/src/gui/editors/BBEditor.cpp b/src/gui/editors/BBEditor.cpp index 02ea125de..db14eecf6 100644 --- a/src/gui/editors/BBEditor.cpp +++ b/src/gui/editors/BBEditor.cpp @@ -22,13 +22,15 @@ * */ +#include "BBEditor.h" + #include #include #include #include #include -#include "BBEditor.h" +#include "ComboBox.h" #include "BBTrackContainer.h" #include "embed.h" #include "MainWindow.h" From 3db3711dcf383bbb336e4e35ff5529265de98bfe Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 22 Jan 2015 18:31:09 +0000 Subject: [PATCH 17/59] fix for 1668 now checks if save to load song --- src/gui/TrackContainerView.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index d8c3a5c40..a52930f83 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -45,6 +45,7 @@ #include "Song.h" #include "StringPairDrag.h" #include "Track.h" +#include "GuiApplication.h" TrackContainerView::TrackContainerView( TrackContainer * _tc ) : @@ -363,7 +364,10 @@ void TrackContainerView::dropEvent( QDropEvent * _de ) else if( type == "projectfile") { - Engine::getSong()->loadProject( value ); + if( gui->mainWindow()->mayChangeProject() ) + { + Engine::getSong()->loadProject( value ); + } _de->accept(); } From 8267ac63160ac24b70edeca8c6f25224193eba2d Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Thu, 22 Jan 2015 17:13:23 -0200 Subject: [PATCH 18/59] Fix beat pattern actions on melodies --- src/tracks/Pattern.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index 10ce2bca1..c39fbdbcd 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -761,12 +761,16 @@ void PatternView::constructContextMenu( QMenu * _cm ) _cm->addAction( embed::getIconPixmap( "edit_rename" ), tr( "Change name" ), this, SLOT( changeName() ) ); - _cm->addSeparator(); - _cm->addAction( embed::getIconPixmap( "step_btn_add" ), - tr( "Add steps" ), m_pat, SLOT( addSteps() ) ); - _cm->addAction( embed::getIconPixmap( "step_btn_remove" ), - tr( "Remove steps" ), m_pat, SLOT( removeSteps() ) ); + if ( m_pat->type() == Pattern::BeatPattern ) + { + _cm->addSeparator(); + + _cm->addAction( embed::getIconPixmap( "step_btn_add" ), + tr( "Add steps" ), m_pat, SLOT( addSteps() ) ); + _cm->addAction( embed::getIconPixmap( "step_btn_remove" ), + tr( "Remove steps" ), m_pat, SLOT( removeSteps() ) ); + } } From 2be8eaa4db77f254beb08995591af8636d4165b6 Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 22 Jan 2015 20:16:00 +0000 Subject: [PATCH 19/59] Proposed fix for 446, select notes in piano roll using timeline --- include/PianoRoll.h | 2 ++ src/gui/editors/PianoRoll.cpp | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 8f1dabdc3..98e074619 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -160,6 +160,8 @@ protected slots: void hidePattern( Pattern* pattern ); + void selectRegionFromPixels( int x, int y ); + signals: void currentPatternChanged(); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 366920df7..679da308c 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -417,6 +417,10 @@ PianoRoll::PianoRoll() : connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int, int ) ), this, SLOT( update() ) ); + + //connection for selecion from timeline + connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), + this, SLOT( selectRegionFromPixels( int, int ) ) ); } @@ -589,6 +593,44 @@ void PianoRoll::hidePattern( Pattern* pattern ) } } +void PianoRoll::selectRegionFromPixels(int x, int y) +{ + + x -= WHITE_KEY_WIDTH; + y -= WHITE_KEY_WIDTH; + + // select an area of notes + int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + int key_num = 0; + m_selectStartTick = pos_ticks; + m_selectedTick = 0; + m_selectStartKey = key_num; + m_selectedKeys = 1; + // change size of selection + + // get tick in which the cursor is posated + pos_ticks = y * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + key_num = 120; + + m_selectedTick = pos_ticks - m_selectStartTick; + if( (int) m_selectStartTick + m_selectedTick < 0 ) + { + m_selectedTick = -static_cast( + m_selectStartTick ); + } + m_selectedKeys = key_num - m_selectStartKey; + if( key_num <= m_selectStartKey ) + { + --m_selectedKeys; + } + + computeSelectedNotes( false ); +} + + + From d569015273251bcbac23dcc0b8bdf2b6a9e18009 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Thu, 22 Jan 2015 22:22:57 +0100 Subject: [PATCH 20/59] Travis: updated name of PPA with MinGW-X packages for Precise --- .travis/linux.win32.before_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/linux.win32.before_install.sh b/.travis/linux.win32.before_install.sh index 02a9be79d..73c14aedd 100644 --- a/.travis/linux.win32.before_install.sh +++ b/.travis/linux.win32.before_install.sh @@ -1,2 +1,2 @@ -sudo add-apt-repository ppa:tobydox/mingw -y +sudo add-apt-repository ppa:tobydox/mingw-x-precise -y sudo apt-get update -qq From c201a41c050ab31e9751154adf4820b87305acaf Mon Sep 17 00:00:00 2001 From: Dave French Date: Fri, 23 Jan 2015 02:16:30 +0000 Subject: [PATCH 21/59] Proposed fix 1416 Drag-and-drop of automatables to Automation Editor --- include/AutomationEditor.h | 4 ++++ include/AutomationTrack.h | 1 + src/gui/editors/AutomationEditor.cpp | 33 ++++++++++++++++++++++++++++ src/tracks/AutomationTrack.cpp | 1 + 4 files changed, 39 insertions(+) diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 64cfeb718..45abfd932 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -70,6 +70,7 @@ public: virtual void saveSettings(QDomDocument & doc, QDomElement & parent); virtual void loadSettings(const QDomElement & parent); + QString nodeName() const { return "automationeditor"; @@ -262,6 +263,9 @@ public: void setCurrentPattern(AutomationPattern* pattern); const AutomationPattern* currentPattern(); + virtual void dropEvent( QDropEvent * _de ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + void open(AutomationPattern* pattern); AutomationEditor* m_editor; diff --git a/include/AutomationTrack.h b/include/AutomationTrack.h index b8d3da38d..f805f1344 100644 --- a/include/AutomationTrack.h +++ b/include/AutomationTrack.h @@ -52,6 +52,7 @@ public: QDomElement & _parent ); virtual void loadTrackSpecificSettings( const QDomElement & _this ); + private: friend class AutomationTrackView; diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index f839eb5a6..4558ff7f0 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -64,6 +64,8 @@ #include "PianoRoll.h" #include "debug.h" #include "MeterModel.h" +#include "StringPairDrag.h" +#include "ProjectJournal.h" QPixmap * AutomationEditor::s_toolDraw = NULL; @@ -239,6 +241,7 @@ void AutomationEditor::loadSettings( const QDomElement & dom_parent) + // qproperty access methods QColor AutomationEditor::gridColor() const @@ -2220,6 +2223,7 @@ AutomationEditorWindow::AutomationEditorWindow() : setFocusPolicy( Qt::StrongFocus ); setFocus(); setWindowIcon( embed::getIconPixmap( "automation" ) ); + setAcceptDrops( true ); } @@ -2282,6 +2286,35 @@ const AutomationPattern* AutomationEditorWindow::currentPattern() return m_editor->currentPattern(); } +void AutomationEditorWindow::dropEvent(QDropEvent *_de) +{ + QString type = StringPairDrag::decodeKey( _de ); + QString val = StringPairDrag::decodeValue( _de ); + if( type == "automatable_model" ) + { + AutomatableModel * mod = dynamic_cast( + Engine::projectJournal()-> + journallingObject( val.toInt() ) ); + if( mod != NULL ) + { + if( m_editor->m_pattern->firstObject() ) + { + m_editor->m_pattern->objectDestroyed( m_editor->m_pattern->firstObject()->id() ); + } + m_editor->m_pattern->addObject( mod ); + setCurrentPattern( m_editor->m_pattern ); + + } + } + + update(); +} + +void AutomationEditorWindow::dragEnterEvent(QDragEnterEvent *_dee) +{ + StringPairDrag::processDragEnterEvent( _dee, "automatable_model" ); +} + void AutomationEditorWindow::open(AutomationPattern* pattern) { setCurrentPattern(pattern); diff --git a/src/tracks/AutomationTrack.cpp b/src/tracks/AutomationTrack.cpp index 2b397862d..1b552aba3 100644 --- a/src/tracks/AutomationTrack.cpp +++ b/src/tracks/AutomationTrack.cpp @@ -127,6 +127,7 @@ void AutomationTrack::loadTrackSpecificSettings( const QDomElement & _this ) + AutomationTrackView::AutomationTrackView( AutomationTrack * _at, TrackContainerView* tcv ) : TrackView( _at, tcv ) { From dfbbcfd38bb03cf279017cf2b213d7fc7e3462ca Mon Sep 17 00:00:00 2001 From: Dave French Date: Fri, 23 Jan 2015 02:38:17 +0000 Subject: [PATCH 22/59] 1416 tidy up --- include/AutomationEditor.h | 1 - include/AutomationTrack.h | 1 - src/gui/editors/AutomationEditor.cpp | 3 +-- src/tracks/AutomationTrack.cpp | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 45abfd932..eca52d2c6 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -70,7 +70,6 @@ public: virtual void saveSettings(QDomDocument & doc, QDomElement & parent); virtual void loadSettings(const QDomElement & parent); - QString nodeName() const { return "automationeditor"; diff --git a/include/AutomationTrack.h b/include/AutomationTrack.h index f805f1344..b8d3da38d 100644 --- a/include/AutomationTrack.h +++ b/include/AutomationTrack.h @@ -52,7 +52,6 @@ public: QDomElement & _parent ); virtual void loadTrackSpecificSettings( const QDomElement & _this ); - private: friend class AutomationTrackView; diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 4558ff7f0..9cfb70b12 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -241,7 +241,6 @@ void AutomationEditor::loadSettings( const QDomElement & dom_parent) - // qproperty access methods QColor AutomationEditor::gridColor() const @@ -2301,9 +2300,9 @@ void AutomationEditorWindow::dropEvent(QDropEvent *_de) { m_editor->m_pattern->objectDestroyed( m_editor->m_pattern->firstObject()->id() ); } + m_editor->m_pattern->clear(); m_editor->m_pattern->addObject( mod ); setCurrentPattern( m_editor->m_pattern ); - } } diff --git a/src/tracks/AutomationTrack.cpp b/src/tracks/AutomationTrack.cpp index 1b552aba3..2b397862d 100644 --- a/src/tracks/AutomationTrack.cpp +++ b/src/tracks/AutomationTrack.cpp @@ -127,7 +127,6 @@ void AutomationTrack::loadTrackSpecificSettings( const QDomElement & _this ) - AutomationTrackView::AutomationTrackView( AutomationTrack * _at, TrackContainerView* tcv ) : TrackView( _at, tcv ) { From f8120cd2fe4805cae35e88c94a3d4b1dd4e98be1 Mon Sep 17 00:00:00 2001 From: Dave French Date: Fri, 23 Jan 2015 18:15:03 +0000 Subject: [PATCH 23/59] Tidy up and remove clearing 1416 --- src/gui/editors/AutomationEditor.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 9cfb70b12..0c8033cb6 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -2223,6 +2223,7 @@ AutomationEditorWindow::AutomationEditorWindow() : setFocus(); setWindowIcon( embed::getIconPixmap( "automation" ) ); setAcceptDrops( true ); + m_toolBar->setAcceptDrops( true ); } @@ -2285,7 +2286,7 @@ const AutomationPattern* AutomationEditorWindow::currentPattern() return m_editor->currentPattern(); } -void AutomationEditorWindow::dropEvent(QDropEvent *_de) +void AutomationEditorWindow::dropEvent( QDropEvent *_de ) { QString type = StringPairDrag::decodeKey( _de ); QString val = StringPairDrag::decodeValue( _de ); @@ -2296,20 +2297,14 @@ void AutomationEditorWindow::dropEvent(QDropEvent *_de) journallingObject( val.toInt() ) ); if( mod != NULL ) { - if( m_editor->m_pattern->firstObject() ) - { - m_editor->m_pattern->objectDestroyed( m_editor->m_pattern->firstObject()->id() ); - } - m_editor->m_pattern->clear(); - m_editor->m_pattern->addObject( mod ); - setCurrentPattern( m_editor->m_pattern ); + m_editor->m_pattern->addObject( mod ); } } update(); } -void AutomationEditorWindow::dragEnterEvent(QDragEnterEvent *_dee) +void AutomationEditorWindow::dragEnterEvent( QDragEnterEvent *_dee ) { StringPairDrag::processDragEnterEvent( _dee, "automatable_model" ); } From f6792d991c51e1957d93ed7ed1591ada807179c4 Mon Sep 17 00:00:00 2001 From: Dave French Date: Fri, 23 Jan 2015 19:46:09 +0000 Subject: [PATCH 24/59] 1416 refresh window --- src/gui/editors/AutomationEditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 0c8033cb6..bde69e950 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -2298,6 +2298,7 @@ void AutomationEditorWindow::dropEvent( QDropEvent *_de ) if( mod != NULL ) { m_editor->m_pattern->addObject( mod ); + setCurrentPattern( m_editor->m_pattern ); } } From d4d15ea567809a702cac5e137766f364d31549ac Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 23 Jan 2015 22:37:12 +0100 Subject: [PATCH 25/59] Update Swedish Translation --- data/locale/sv.ts | 268 +++++++++++++++++++++++----------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 6f57e6f6f..2d71c2946 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -5,7 +5,7 @@ AboutDialog About LMMS - + Om LMMS Version %1 (%2/%3, Qt %4, %5) @@ -17,15 +17,15 @@ LMMS - easy music production for everyone - + LMMS - enkel musikproduktion för alla Authors - + Utvecklare Translation - + Översättning Current language not translated (or native English). @@ -35,11 +35,11 @@ If you're interested in translating LMMS in another language or want to imp License - + Licens Copyright (c) 2004-2014, LMMS developers - + Copyright (c) 2004-2014, LMMS utvecklare <html><head/><body><p><a href="http://lmms.io"><span style=" text-decoration: underline; color:#0000ff;">http://lmms.io</span></a></p></body></html> @@ -47,15 +47,15 @@ If you're interested in translating LMMS in another language or want to imp LMMS - + LMMS Involved - + Involverad Contributors ordered by number of commits: - + Utvecklare ordnade efter mängd bidrag: @@ -78,19 +78,19 @@ If you're interested in translating LMMS in another language or want to imp LEFT - + VÄNSTER Left gain: - + Vänster volym: RIGHT - + HÖGER Right gain: - + Höger volym: @@ -105,11 +105,11 @@ If you're interested in translating LMMS in another language or want to imp Left gain - + Vänster volym Right gain - + Höger volym @@ -127,19 +127,19 @@ If you're interested in translating LMMS in another language or want to imp AudioFileProcessorView Open other sample - + Oppna annan ljudfil Click here, if you want to open another audio-file. A dialog will appear where you can select your file. Settings like looping-mode, start and end-points, amplify-value, and so on are not reset. So, it may not sound like the original sample. - + Klicka här för att öppna en anna ljud fil. En dialogvisas där du väljer din fil. Inställningar som looping, start och slutpunkter, volym och sådant omställs inte. Därför låter det kanske inte som originalfilen. Reverse sample - + Spela baklänges If you enable this button, the whole sample is reversed. This is useful for cool effects, e.g. a reversed crash. - + Den här knappen gör att ljudfilen spelas baklänges. Den kan användas för intressanta effeker t.ex. en baklänges cymbal. Amplify: @@ -147,7 +147,7 @@ If you're interested in translating LMMS in another language or want to imp With this knob you can set the amplify ratio. When you set a value of 100% your sample isn't changed. Otherwise it will be amplified up or down (your actual sample-file isn't touched!) - + Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men källfilen förändras inte. Startpoint: @@ -155,51 +155,51 @@ If you're interested in translating LMMS in another language or want to imp Endpoint: - + Slutpunkt: Continue sample playback across notes - + Forsätt spela ljudfil över noter Enabling this option makes the sample continue playing across different notes - if you change pitch, or the note length stops before the end of the sample, then the next note played will continue where it left off. To reset the playback to the start of the sample, insert a note at the bottom of the keyboard (< 20 Hz) - + Denna inställningen gör att ljudfilen förtsätter spela över noter. Om en not avslutas före ljudfilen är slut fortsätter nästa not där den förra slutade. Om du vill starta från början av ljudfilen innan den spelat färdigt, placera en not på botten av pianot (vid 20Hz) Disable loop - + Avaktivera looping This button disables looping. The sample plays only once from start to end. - + Den här knappen avaktiverar looping.Ljudfilen spelas bara en gång från starttill slut. Enable loop - + Aktivera looping This button enables forwards-looping. The sample loops between the end point and the loop point. - + Den här knappen aktiverar looping. Ljudfilen loopar mellan slutpunkten och looppunkten. This button enables ping-pong-looping. The sample loops backwards and forwards between the end point and the loop point. - + Den här knappen aktiverar "ping-pong" looping. Ljudfilen spelar från start till slut, och sen tilbaks, och fortsäter så. With this knob you can set the point where AudioFileProcessor should begin playing your sample. - + Med den här vreden ställer du in vartifrån ljudfilen ska börja spela. With this knob you can set the point where AudioFileProcessor should stop playing your sample. - + Med den här vreden ställer du in vart ljudfilen slutar spela. Loopback point: - + Loopback punkt: With this knob you can set the point where the loop starts. - + Den här vreden ställer in vart loopen startar. @@ -213,19 +213,19 @@ If you're interested in translating LMMS in another language or want to imp AudioJack JACK client restarted - + JACK klienten omstartades LMMS was kicked by JACK for some reason. Therefore the JACK backend of LMMS has been restarted. You will have to make manual connections again. - + LMMS blev bortkopplat från JACK. LMMS JACK backend omstartades därfor. Du får manuellt koppla om igen. JACK server down - + JACK server nerstängd The JACK server seems to have been shutdown and starting a new instance failed. Therefore LMMS is unable to proceed. You should save your project and restart JACK and LMMS. - + JACK servern stängde av och det gick inte starta en ny. LMMS kan inte fortsätta. Du bör spara ditt projekt och starta om både JACK och LMMS. CLIENT-NAME @@ -251,7 +251,7 @@ If you're interested in translating LMMS in another language or want to imp AudioPortAudio::setupWidget BACKEND - + BACKEND DEVICE @@ -284,7 +284,7 @@ If you're interested in translating LMMS in another language or want to imp &Copy value (%1%2) - + Kopiera värder (%1%2) &Paste value (%1%2) @@ -292,42 +292,42 @@ If you're interested in translating LMMS in another language or want to imp Edit song-global automation - + Redigera global automation Connected to %1 - + Kopplad till %1 Connected to controller - + Kopplad till controller Edit connection... - + Redigera koppling... Remove connection - + Ta bort koppling Connect to controller... - + Koppla till kontroller... Remove song-global automation - + Ta bort gloabal automation Remove all linked controls - + Ta bort alla kopplade kontroller AutomationEditor Please open an automation pattern with the context menu of a control! - + Öppna ett mönster ifrån en kontrollers kontext meny! Values copied @@ -346,7 +346,7 @@ If you're interested in translating LMMS in another language or want to imp Click here if you want to play the current pattern. This is useful while editing it. The pattern is automatically looped when the end is reached. - + Clicka här för att spela det aktuella mönstret. Det härär hjälpsamt närman redigerar. Mönstret spelas från början igen när de nått sitt slut. Stop playing of current pattern (Space) @@ -354,75 +354,75 @@ If you're interested in translating LMMS in another language or want to imp Click here if you want to stop playing of the current pattern. - + Klicka här för att stoppa uppspelning av de aktuella mönstret. Draw mode (Shift+D) - + Ritläge (Shift+D) Erase mode (Shift+E) - + Suddläge (Shift+E) Flip vertically - + Spegla vertikalt Flip horizontally - + Spegla horizontellt Click here and the pattern will be inverted.The points are flipped in the y direction. - + Klicka här för att spegla mönstret. Punkterna förflyttas på y-axeln Click here and the pattern will be reversed. The points are flipped in the x direction. - + Klicka här för att spegla mönstret. Punkterna förflyttas på x-axeln Click here and draw-mode will be activated. In this mode you can add and move single values. This is the default mode which is used most of the time. You can also press 'Shift+D' on your keyboard to activate this mode. - + Klicka här för att aktivera ritläget. I detta läget kan du lägga till och förflytta individuella värden. Det här är standardläget. Det går också att trycka 'Shift+D' på tangentborded för att aktivera detta läget. Click here and erase-mode will be activated. In this mode you can erase single values. You can also press 'Shift+E' on your keyboard to activate this mode. - + Klicka här för att aktivera suddläget. I detta läget kan du ta bort individuella värden. Det går också att trycka 'Shift+E' på tangentborded för att aktivera detta läget. Discrete progression - + Diskret talföljd Linear progression - + Linjär talföljd Cubic Hermite progression - + Cubic Hermite talföljd Tension value for spline - + Spänning i mönstrets spline A higher tension value may make a smoother curve but overshoot some values. A low tension value will cause the slope of the curve to level off at each control point. - + Högre spänning ger en mjuk kurva som ibland missar individuella punkter. Med lägre spänning planar kurvan ut nära punkterna. Click here to choose discrete progressions for this automation pattern. The value of the connected object will remain constant between control points and be set immediately to the new value when each control point is reached. - + Klicka här för att aktivera diskret talföljd. Värdet är konstant mella kontroll punkter och ändras direkt när en ny kontrollpunkt nås. Click here to choose linear progressions for this automation pattern. The value of the connected object will change at a steady rate over time between control points to reach the correct value at each control point without a sudden change. - + Klicka här för att aktivera linjär talföljd. Värdet ändras vid en stadig takt mellan kontrollpunkter för att gradvis nå nästa värde. Click here to choose cubic hermite progressions for this automation pattern. The value of the connected object will change in a smooth curve and ease in to the peaks and valleys. - + Klicka här för att aktivera cubic hermite talföljd. Värdet följer en mjuk kurva mellan kontrollpunkter. Cut selected values (Ctrl+X) - klipp ut valda värden (ctrl+X) + Klipp ut valda värden (ctrl+X) Copy selected values (Ctrl+C) @@ -430,57 +430,57 @@ If you're interested in translating LMMS in another language or want to imp Paste values from clipboard Ctrl+V) - + Klistra värden (Ctrl+V) Click here and selected values will be cut into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Klicka här för att klippa de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. Click here and selected values will be copied into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Klicka här för att kopiera de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. Click here and the values from the clipboard will be pasted at the first visible measure. - + Klicka här för att klistra kopierade värderna vid den första synliga metern. Tension: - + Spänning: Automation Editor - no pattern - + Redigera Automation - inget mönster Automation Editor - %1 - + Redigera Automation - %1 AutomationPattern Drag a control while pressing <Ctrl> - + Dra en kontroll samtidigt som du håller <Ctrl> Model is already connected to this pattern. - + Modellen är redan kopplad till detta mönstret. AutomationPatternView double-click to open this pattern in automation editor - + dubbelklicka för att öppna det här mönstret för redigering Open in Automation editor - + Öppna för att redigera Clear - + Rensa Reset name @@ -492,76 +492,76 @@ If you're interested in translating LMMS in another language or want to imp %1 Connections - + %1 Kopplingar Disconnect "%1" - + Avkoppla "%1" Set/clear record - + Set/rensa inspelning Flip Vertically (Visible) - + Spegla Vertikalt (Synligt) Flip Horizontally (Visible) - + Spegla Horizontellt (Synligt) AutomationTrack Automation track - + Automation spår BBEditor Beat+Bassline Editor - + Redigera Trummor+Bas Play/pause current beat/bassline (Space) - + Spela/pause Trummor+Bas Stop playback of current beat/bassline (Space) - + Avsluta uppspelning av Trummor+Bas Click here to play the current beat/bassline. The beat/bassline is automatically looped when its end is reached. - + Klicka här för att spela Trummor/Bas.Mönstret loopar när det nåt sitt slut. Click here to stop playing of current beat/bassline. - + Klicka här för att sluta spela trummor/bas. Add beat/bassline - + Lägg till trummor/bas Add automation-track - + Lägg till automationsmönster Remove steps - + Ta bort steg Add steps - + Lägg till steg BBTCOView Open in Beat+Bassline-Editor - + Öppna för att redigera Trummor+Bas Reset name @@ -577,99 +577,99 @@ If you're interested in translating LMMS in another language or want to imp Reset color to default - + Byt färg till standard BBTrack Beat/Bassline %1 - + Trummor/Bas %1 Clone of %1 - + Kopia av %1 BassBoosterControlDialog FREQ - + FREQ Frequency: - + Frekven: GAIN - + VOL Gain: - + Volym: RATIO - + RATIO Ratio: - + Ratio: BassBoosterControls Frequency - + Frekvens Gain - + Volym Ratio - + Ratio BitcrushControlDialog IN - + IN OUT - + UT GAIN - + VOL Input Gain: - + Input Volym: NOIS - + BRUS Input Noise: - + Input brus: Output Gain: - + Output Volym CLIP - + CLIP Output Clip: - + Output Clip: Rate @@ -685,11 +685,11 @@ If you're interested in translating LMMS in another language or want to imp Depth - + Djup Depth Enabled - + Djup aktiverat Enable bitdepth-crushing @@ -709,11 +709,11 @@ If you're interested in translating LMMS in another language or want to imp Levels - + Nivåer Levels: - + Nivåer: @@ -724,7 +724,7 @@ If you're interested in translating LMMS in another language or want to imp Help (not available) - + Hjälp (inte tillgängligt) @@ -735,29 +735,29 @@ If you're interested in translating LMMS in another language or want to imp Click here to show or hide the graphical user interface (GUI) of Carla. - + Klicka här för att öppna eller stänga Carlas GUI. Controller Controller %1 - + Kontroller %1 ControllerConnectionDialog Connection Settings - + Kopplingsinställningar MIDI CONTROLLER - + MIDI KONTROLLER Input channel - + Input kanal CHANNEL @@ -765,15 +765,15 @@ If you're interested in translating LMMS in another language or want to imp Input controller - + Input kontroller CONTROLLER - + KONTROLLER Auto Detect - + Upptäck automatiskt MIDI-devices to receive MIDI-events from @@ -781,7 +781,7 @@ If you're interested in translating LMMS in another language or want to imp USER CONTROLLER - + ANVÄNDARKONTROLLER MAPPING FUNCTION @@ -789,7 +789,7 @@ If you're interested in translating LMMS in another language or want to imp OK - + OK Cancel @@ -820,7 +820,7 @@ If you're interested in translating LMMS in another language or want to imp Confirm delete? There are existing connection(s) associted with this controller. There is no way to undo. - + Vill du verkligen ta bort? Det finns kopplingar till den här kotrollen, och operationen går inte ångra. @@ -831,15 +831,15 @@ If you're interested in translating LMMS in another language or want to imp Controllers are able to automate the value of a knob, slider, and other controls. - + Kontroller kan automatisera värdet på en vred, reglage, och andra kontroller Rename controller - + Byt namn på kontroller Enter the new name for this controller - + Skriv nya namnet på kontrollern &Remove this plugin From 28a51968a32c86c16ffcd6697e77ad4827c141b2 Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 23 Jan 2015 23:00:26 +0100 Subject: [PATCH 26/59] =?UTF-8?q?Gain:=20Volym>F=C3=B6st=C3=A4rkning=20Amp?= =?UTF-8?q?lification:=20Volym>Amplifiering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/locale/sv.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 2d71c2946..d1772edf3 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -82,7 +82,7 @@ If you're interested in translating LMMS in another language or want to imp Left gain: - Vänster volym: + Vänster förstärkning: RIGHT @@ -90,7 +90,7 @@ If you're interested in translating LMMS in another language or want to imp Right gain: - Höger volym: + Höger förstärkning: @@ -105,11 +105,11 @@ If you're interested in translating LMMS in another language or want to imp Left gain - Vänster volym + Vänster förstärkning Right gain - Höger volym + Höger förstärkning @@ -131,7 +131,7 @@ If you're interested in translating LMMS in another language or want to imp Click here, if you want to open another audio-file. A dialog will appear where you can select your file. Settings like looping-mode, start and end-points, amplify-value, and so on are not reset. So, it may not sound like the original sample. - Klicka här för att öppna en anna ljud fil. En dialogvisas där du väljer din fil. Inställningar som looping, start och slutpunkter, volym och sådant omställs inte. Därför låter det kanske inte som originalfilen. + Klicka här för att öppna en anna ljud fil. En dialogvisas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. Reverse sample @@ -607,7 +607,7 @@ If you're interested in translating LMMS in another language or want to imp Gain: - Volym: + Förstärkning: RATIO @@ -626,7 +626,7 @@ If you're interested in translating LMMS in another language or want to imp Gain - Volym + Förstärkning Ratio @@ -649,7 +649,7 @@ If you're interested in translating LMMS in another language or want to imp Input Gain: - Input Volym: + Input Förstärkning: NOIS @@ -661,7 +661,7 @@ If you're interested in translating LMMS in another language or want to imp Output Gain: - Output Volym + Output Förstärkning CLIP From e2a2d27bbaf9bdf95dad313a7f4c9d5764d82a82 Mon Sep 17 00:00:00 2001 From: Dave French Date: Sat, 24 Jan 2015 06:30:23 +0000 Subject: [PATCH 27/59] 446 change parameter names --- include/PianoRoll.h | 2 +- src/gui/editors/PianoRoll.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 98e074619..6260eaa7e 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -160,7 +160,7 @@ protected slots: void hidePattern( Pattern* pattern ); - void selectRegionFromPixels( int x, int y ); + void selectRegionFromPixels( int xStart, int xEnd ); signals: diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 679da308c..0d3540975 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -593,14 +593,14 @@ void PianoRoll::hidePattern( Pattern* pattern ) } } -void PianoRoll::selectRegionFromPixels(int x, int y) +void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) { - x -= WHITE_KEY_WIDTH; - y -= WHITE_KEY_WIDTH; + xStart -= WHITE_KEY_WIDTH; + xEnd -= WHITE_KEY_WIDTH; // select an area of notes - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = xStart * MidiTime::ticksPerTact() / m_ppt + m_currentPosition; int key_num = 0; m_selectStartTick = pos_ticks; @@ -610,7 +610,7 @@ void PianoRoll::selectRegionFromPixels(int x, int y) // change size of selection // get tick in which the cursor is posated - pos_ticks = y * MidiTime::ticksPerTact() / m_ppt + + pos_ticks = xEnd * MidiTime::ticksPerTact() / m_ppt + m_currentPosition; key_num = 120; From 91c76f342b00ebb1c0d0845b9fc1b6d3b57bc71b Mon Sep 17 00:00:00 2001 From: SecondFlight Date: Sat, 24 Jan 2015 20:09:07 -0500 Subject: [PATCH 28/59] Added a song to data/projects/CoolSongs The song that will (hopefully) be added: https://soundcloud.com/second_flight/krem-kaakkuja-remix --- ...i - Krem Kaakkuja (Second Flight Remix).mmpz | Bin 0 -> 46365 bytes data/projects/CoolSongs/LICENSES.TXT | 8 ++++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz diff --git a/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz b/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz new file mode 100644 index 0000000000000000000000000000000000000000..0a2ecb2c9364364a586b9a72d8acd2920696ca39 GIT binary patch literal 46365 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 zఊ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 z Date: Sun, 25 Jan 2015 16:10:22 +0100 Subject: [PATCH 29/59] Update sv.ts --- data/locale/sv.ts | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index d1772edf3..9950aed37 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -55,7 +55,7 @@ If you're interested in translating LMMS in another language or want to imp Contributors ordered by number of commits: - Utvecklare ordnade efter mängd bidrag: + Medverkande, ordnade efter mängd bidrag: @@ -147,7 +147,7 @@ If you're interested in translating LMMS in another language or want to imp With this knob you can set the amplify ratio. When you set a value of 100% your sample isn't changed. Otherwise it will be amplified up or down (your actual sample-file isn't touched!) - Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men källfilen förändras inte. + Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men originalfilen förändras inte. Startpoint: @@ -206,7 +206,7 @@ If you're interested in translating LMMS in another language or want to imp AudioFileProcessorWaveView Sample length: - + Ljudfilens lengd: @@ -1468,7 +1468,7 @@ Right clicking will bring up a context menu where you can change the order in wh Click here for a user-defined wave. Afterwards, drag an according sample-file onto the LFO graph. - + Klicka här för att använda en annan vågform. Dra sedan en ljudfil till LFO grafen FREQ x 100 @@ -1504,7 +1504,7 @@ Right clicking will bring up a context menu where you can change the order in wh Drag a sample from somewhere and drop it in this window. - + Dra en ljudfil till det här fönstret Click here for random wave. @@ -1958,11 +1958,11 @@ Please make sure you have write-permission to the file and the directory contain Loading sample - + Laddar ljudfil Please wait, loading sample for preview... - + Ljudfilen laddas för förhandsvisning... --- Factory files --- @@ -3559,19 +3559,19 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. My Samples - + Mina Ljudfiler My Presets - + Mina Presets My Home - + Mit Hem My Computer - + Min Dator Root Directory @@ -3579,15 +3579,15 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. &File - + &Fil &Recently Opened Projects - + &Nyligen Öppnade Project Save as New &Version - + Spara som ny &Version E&xport Tracks... @@ -3599,15 +3599,15 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. What's This? - + Vad är det här? Open Project - + Öppna Project Save Project - + SparaProject @@ -5323,7 +5323,7 @@ Reason: "%2" SampleTrack Sample track - + Ljudfil spår Volume @@ -5748,7 +5748,7 @@ Latency: %2 ms Add sample-track - + Lägg til ljudfil-spår Add automation-track @@ -6621,7 +6621,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Click to load a waveform from a sample file - + Klicka för att ladda in en vågform från en ljudfil Phase left @@ -6802,7 +6802,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle audioFileProcessor Reverse sample - + Spela baklänges Amplify @@ -6810,11 +6810,11 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Start of sample - + Start på ljudfil End of sample - + Slut på ljudfil Stutter @@ -6846,21 +6846,21 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Sample not found: %1 - + Ljudfil hittades inte: %1 bitInvader Samplelength - + Ljudfilslängd bitInvaderView Sample Length - + Ljudfilens längd Sine wave @@ -6868,7 +6868,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Triangle wave - triganelvåg + Triganelvåg Saw wave From 0fe2ab55331280273e2e114b274f9ba078f76e11 Mon Sep 17 00:00:00 2001 From: Dave French Date: Sun, 25 Jan 2015 20:07:53 +0000 Subject: [PATCH 30/59] Proposed fix 1685 Automation Copy/Paste from Context Menu --- src/core/Track.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 426676f0e..212c96ee6 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -49,6 +49,7 @@ #include "AutomationPattern.h" #include "AutomationTrack.h" +#include "AutomationEditor.h" #include "BBEditor.h" #include "BBTrack.h" #include "BBTrackContainer.h" @@ -207,6 +208,8 @@ void TrackContentObject::paste() restoreState( *( Clipboard::getContent( nodeName() ) ) ); movePosition( pos ); } + AutomationPattern::resolveAllIDs(); + GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange(); } From cebf8bfd59da8788645f281e1d59b9a9ac72ee0d Mon Sep 17 00:00:00 2001 From: Dave French Date: Sun, 25 Jan 2015 20:37:00 +0000 Subject: [PATCH 31/59] Renamed parameters on selectRegionFromPixels --- include/TrackContainerView.h | 2 +- src/gui/TrackContainerView.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index 51b8ca0fa..42e56128f 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -131,7 +131,7 @@ public slots: /// \param x /// \param y /// Use the rubber band to select TCO from all tracks using x, y pixels - void selectRegionFromPixels(int x, int y); + void selectRegionFromPixels(int xStart, int xEnd); /// /// \brief stopRubberBand diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index 8872512c9..778577e18 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -313,11 +313,11 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) arg( Track::SampleTrack ) ); } -void TrackContainerView::selectRegionFromPixels(int x, int y) +void TrackContainerView::selectRegionFromPixels(int xStart, int xEnd) { m_rubberBand->setEnabled( true ); m_rubberBand->show(); - m_rubberBand->setGeometry( min( x, y ), 0, max( x, y ) - min( x, y ), std::numeric_limits::max() ); + m_rubberBand->setGeometry( min( xStart, xEnd ), 0, max( xStart, xEnd ) - min( xStart, xEnd ), std::numeric_limits::max() ); } void TrackContainerView::stopRubberBand() From e51da26a1a657bba8f13f46c02c077440c53b9fa Mon Sep 17 00:00:00 2001 From: Dave French Date: Mon, 26 Jan 2015 22:23:19 +0000 Subject: [PATCH 32/59] Automation editior undo --- src/gui/editors/AutomationEditor.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index bde69e950..7c4b77dbf 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -447,7 +447,6 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) { return; } - if( mouseEvent->y() > TOP_MARGIN ) { float level = getLevel( mouseEvent->y() ); @@ -493,6 +492,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) if( mouseEvent->button() == Qt::LeftButton && m_editMode == DRAW ) { + m_pattern->addJournalCheckPoint(); // Connect the dots if( mouseEvent->modifiers() & Qt::ShiftModifier ) { @@ -537,6 +537,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) m_editMode == DRAW ) || m_editMode == ERASE ) { + m_pattern->addJournalCheckPoint(); // erase single value if( it != time_map.end() ) { @@ -566,6 +567,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) else if( mouseEvent->button() == Qt::LeftButton && m_editMode == MOVE ) { + m_pattern->addJournalCheckPoint(); // move selection (including selected values) // save position where move-process began @@ -1660,6 +1662,7 @@ void AutomationEditor::setProgressionType(AutomationPattern::ProgressionTypes ty { if (validPattern()) { + m_pattern->addJournalCheckPoint(); QMutexLocker m(&m_patternMutex); m_pattern->setProgressionType(type); Engine::getSong()->setModified(); @@ -1799,6 +1802,7 @@ void AutomationEditor::cutSelectedValues() return; } + m_pattern->addJournalCheckPoint(); m_valuesToCopy.clear(); timeMap selected_values; @@ -1828,6 +1832,7 @@ void AutomationEditor::pasteValues() QMutexLocker m( &m_patternMutex ); if( validPattern() && !m_valuesToCopy.isEmpty() ) { + m_pattern->addJournalCheckPoint(); for( timeMap::iterator it = m_valuesToCopy.begin(); it != m_valuesToCopy.end(); ++it ) { @@ -1854,6 +1859,7 @@ void AutomationEditor::deleteSelectedValues() return; } + m_pattern->addJournalCheckPoint(); timeMap selected_values; getSelectedValues( selected_values ); From a30c32f8d84fbc516b25eb34a5895ab38989609d Mon Sep 17 00:00:00 2001 From: Dave French Date: Tue, 27 Jan 2015 00:11:23 +0000 Subject: [PATCH 33/59] Undo of TCO changes in song editor --- src/core/Track.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 426676f0e..2d0f80c5f 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1436,6 +1436,7 @@ void TrackContentWidget::mousePressEvent( QMouseEvent * _me ) else if( _me->button() == Qt::LeftButton && !m_trackView->trackContainerView()->fixedTCOs() ) { + getTrack()->addJournalCheckPoint(); const MidiTime pos = getPosition( _me->x() ).getTact() * MidiTime::ticksPerTact(); TrackContentObject * tco = getTrack()->createTCO( pos ); From 57460c91c3802196c928521457589c3a37a3060b Mon Sep 17 00:00:00 2001 From: Dave French Date: Tue, 27 Jan 2015 00:28:40 +0000 Subject: [PATCH 34/59] bb patern --- src/tracks/Pattern.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index c39fbdbcd..c348f50b8 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -838,6 +838,7 @@ void PatternView::mousePressEvent( QMouseEvent * _me ) } else // note at step found { + m_pat->addJournalCheckPoint(); if( n->length() < 0 ) { n->setLength( 0 ); // set note as enabled beat note From ea80d01f8b445495ecdfe5266971dedb67cff6cd Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 21 Jan 2015 13:04:19 +0100 Subject: [PATCH 35/59] Adds dialog when project is opened that was made with a different version of LMMS Remove Commented Out Code Update DataFile.cpp Update DataFile.cpp Update DataFile.cpp Changes per tresf's advice, adds comments Git??? Please work :/ Update DataFile.cpp Adds dialog when project is opened that was made with a different version of LMMS Remove Commented Out Code Update DataFile.cpp Update DataFile.cpp Update DataFile.cpp Changes per tresf's advice, adds comments Git??? Please work :/ Update DataFile.cpp --- src/core/DataFile.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 0cd7a5703..a9739f412 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -37,6 +37,7 @@ #include "ConfigManager.h" #include "ProjectVersion.h" +#include "ProjectVersion.h" #include "SongEditor.h" #include "Effect.h" #include "lmmsversion.h" @@ -779,10 +780,35 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) m_type = type( root.attribute( "type" ) ); m_head = root.elementsByTagName( "head" ).item( 0 ).toElement(); - if( root.hasAttribute( "creatorversion" ) && - root.attribute( "creatorversion" ) != LMMS_VERSION ) + + if( root.hasAttribute( "creatorversion" ) ) { - upgrade(); + //compareType defaults to Build,so it doesn't have to be set here + ProjectVersion createdWith = root.attribute( "creatorversion" ); + ProjectVersion openedWith = LMMS_VERSION;; + + if (createdWith != openedWith) + { + //Only one compareType needs to be set, and "[The] ProjectVersion return type + //from the setCompareType(...) function [...] saves a few lines of code!" (@tresf) + if ( createdWith.setCompareType(Minor) != openedWith) + { + QMessageBox::information( NULL, + SongEditor::tr( "Project Version Mismatch" ), + SongEditor::tr( + "This project was created with " + "LMMS version %1, but version %2 " + "is installed") + .arg( root.attribute( "creatorversion" ) ) + .arg( LMMS_VERSION ) ); + } + + //The upgrade needs to happen after the warning as it updates the project version. + if( createdWith.setCompareType(Build) < openedWith ) + { + upgrade(); + } + } } m_content = root.elementsByTagName( typeName( m_type ) ). From 0847919214fa2f5f023f230514ba7dba955a9dca Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 26 Jan 2015 09:39:03 +0100 Subject: [PATCH 36/59] Adds GUI check around GUI calls in DataFile.cpp --- src/core/DataFile.cpp | 69 ++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index a9739f412..c39e78296 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -125,14 +125,18 @@ DataFile::DataFile( const QString & _fileName ) : QFile inFile( _fileName ); if( !inFile.open( QIODevice::ReadOnly ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not open file" ), - SongEditor::tr( "Could not open file %1. You probably " - "have no permissions to read this " - "file.\n Please make sure to have at " - "least read permissions to the file " - "and try again." ).arg( _fileName ) ); - return; + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not open file" ), + SongEditor::tr( "Could not open file %1. You probably " + "have no permissions to read this " + "file.\n Please make sure to have at " + "least read permissions to the file " + "and try again." ).arg( _fileName ) ); + } + + return; } loadData( inFile.readAll(), _fileName ); @@ -220,11 +224,15 @@ bool DataFile::writeFile( const QString& filename ) if( !outfile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not write file" ), - SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " - "write to this file. Please make sure you have write-access to " - "the file and try again." ).arg( fullName ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not write file" ), + SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " + "write to this file. Please make sure you have write-access to " + "the file and try again." ).arg( fullName ) ); + } + return false; } @@ -766,12 +774,16 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) if( line >= 0 && col >= 0 ) { qWarning() << "at line" << line << "column" << errorMsg; - QMessageBox::critical( NULL, - SongEditor::tr( "Error in file" ), - SongEditor::tr( "The file %1 seems to contain " - "errors and therefore can't be " - "loaded." ). - arg( _sourceFile ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Error in file" ), + SongEditor::tr( "The file %1 seems to contain " + "errors and therefore can't be " + "loaded." ). + arg( _sourceFile ) ); + } + return; } } @@ -793,14 +805,17 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) //from the setCompareType(...) function [...] saves a few lines of code!" (@tresf) if ( createdWith.setCompareType(Minor) != openedWith) { - QMessageBox::information( NULL, - SongEditor::tr( "Project Version Mismatch" ), - SongEditor::tr( - "This project was created with " - "LMMS version %1, but version %2 " - "is installed") - .arg( root.attribute( "creatorversion" ) ) - .arg( LMMS_VERSION ) ); + if( Engine::hasGUI() ) + { + QMessageBox::information( NULL, + SongEditor::tr( "Project Version Mismatch" ), + SongEditor::tr( + "This project was created with " + "LMMS version %1, but version %2 " + "is installed") + .arg( root.attribute( "creatorversion" ) ) + .arg( LMMS_VERSION ) ); + } } //The upgrade needs to happen after the warning as it updates the project version. From 6ec2ece4a4af147ef3a3c995e3651f2668782f60 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 27 Jan 2015 11:32:39 +0100 Subject: [PATCH 37/59] Update code style for project version check. --- src/core/DataFile.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index c39e78296..8db694367 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -795,14 +795,13 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) if( root.hasAttribute( "creatorversion" ) ) { - //compareType defaults to Build,so it doesn't have to be set here + // compareType defaults to Build,so it doesn't have to be set here ProjectVersion createdWith = root.attribute( "creatorversion" ); ProjectVersion openedWith = LMMS_VERSION;; - if (createdWith != openedWith) + if ( createdWith != openedWith ) { - //Only one compareType needs to be set, and "[The] ProjectVersion return type - //from the setCompareType(...) function [...] saves a few lines of code!" (@tresf) + // only one compareType needs to be set, and we can compare on one line because setCompareType returns ProjectVersion if ( createdWith.setCompareType(Minor) != openedWith) { if( Engine::hasGUI() ) @@ -818,7 +817,7 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) } } - //The upgrade needs to happen after the warning as it updates the project version. + // the upgrade needs to happen after the warning as it updates the project version. if( createdWith.setCompareType(Build) < openedWith ) { upgrade(); From 9b1e89ae21e631977957c293b95063b078545acf Mon Sep 17 00:00:00 2001 From: Dave French Date: Tue, 27 Jan 2015 11:18:25 +0000 Subject: [PATCH 38/59] Proposed fix 710 --- src/gui/dialogs/VersionedSaveDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index ae7f5305e..476046371 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -72,7 +72,7 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, bool VersionedSaveDialog::changeFileNameVersion(QString &fileName, bool increment ) { - static QRegExp regexp( "-\\d+(\\.\\w+)?$" ); + static QRegExp regexp( "[- ]\\d+(\\.\\w+)?$" ); int idx = regexp.indexIn( fileName ); // For file names without extension (no ".mmpz") From ff2617b0bd28e0c8b59c33f3990bb151970c557c Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Wed, 28 Jan 2015 00:52:17 -0200 Subject: [PATCH 39/59] Fix crash when removing last channel Sometimes the last channel still had processing to do when it got deleted --- src/core/FxMixer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 00143b2ee..5a2c8a272 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -529,7 +529,10 @@ FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel ) void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch ) { - if( m_fxChannels[_ch]->m_muteModel.value() == false ) + // The first check is for the case where the last fxchannel was deleted but + // there was a race condition where it had to be processed. + if( _ch < m_fxChannels.size() && + m_fxChannels[_ch]->m_muteModel.value() == false ) { m_fxChannels[_ch]->m_lock.lock(); MixHelpers::add( m_fxChannels[_ch]->m_buffer, _buf, Engine::mixer()->framesPerPeriod() ); From 56635c1fcf0d6fd2d13c4f0403fa1e0e0e9a6d22 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 06:35:52 +0000 Subject: [PATCH 40/59] Proposed fix for 1695 Cannot save templates --- src/gui/MainWindow.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index cccc7bd39..b40674551 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -830,8 +830,13 @@ bool MainWindow::saveProjectAs() if( sfd.exec () == FileDialog::Accepted && !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" ) { + QString fname = sfd.selectedFiles()[0] ; + if( sfd.selectedNameFilter().contains( "(*.mpt)" ) ) + { + fname += ".mpt"; + } Engine::getSong()->guiSaveProjectAs( - sfd.selectedFiles()[0] ); + fname ); return( true ); } return( false ); From 7c0ab622f1a930172a86e940ccae020dd5be9aca Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 12:16:21 +0000 Subject: [PATCH 41/59] Proposed fix for 1595 Instrument track activity LED lights when muted --- include/FadeButton.h | 1 + include/InstrumentTrack.h | 1 + src/gui/widgets/FadeButton.cpp | 5 +++++ src/tracks/InstrumentTrack.cpp | 15 +++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/include/FadeButton.h b/include/FadeButton.h index 6e7371f9f..4f05b3491 100644 --- a/include/FadeButton.h +++ b/include/FadeButton.h @@ -39,6 +39,7 @@ public: _activated_color, QWidget * _parent ); virtual ~FadeButton(); + void setActiveColor( const QColor & activated_color ); public slots: diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index 16536c081..85a19c3de 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -225,6 +225,7 @@ protected slots: void updateBaseNote(); void updatePitch(); void updatePitchRange(); + void muteHasChanged(); private: diff --git a/src/gui/widgets/FadeButton.cpp b/src/gui/widgets/FadeButton.cpp index 3495ae959..4fea14f97 100644 --- a/src/gui/widgets/FadeButton.cpp +++ b/src/gui/widgets/FadeButton.cpp @@ -55,6 +55,11 @@ FadeButton::~FadeButton() { } +void FadeButton::setActiveColor( const QColor & activated_color ) +{ + m_activatedColor = activated_color; +} + diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index cd598529e..a527e4300 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -124,6 +124,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : connect( &m_baseNoteModel, SIGNAL( dataChanged() ), this, SLOT( updateBaseNote() ) ); connect( &m_pitchModel, SIGNAL( dataChanged() ), this, SLOT( updatePitch() ) ); connect( &m_pitchRangeModel, SIGNAL( dataChanged() ), this, SLOT( updatePitchRange() ) ); + connect( &m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteHasChanged() ) ); m_effectChannelModel.setRange( 0, Engine::fxMixer()->numChannels()-1, 1); @@ -136,6 +137,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : setName( tr( "Default preset" ) ); + } @@ -549,6 +551,19 @@ void InstrumentTrack::updatePitchRange() processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerDataEntry, midiPitchRange() ) ); } +void InstrumentTrack::muteHasChanged() +{ + if( m_mutedModel.value() ) + { + m_fb->setActiveColor( QColor( "red" ) ); + } else + { + m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::BrightText ) ); + } + +} + From 9fee116fa7886160ba1f42002be46a853d4198f1 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 12:21:57 +0000 Subject: [PATCH 42/59] 1595 removed accidental blank line --- src/tracks/InstrumentTrack.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index a527e4300..6d5a3056d 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -137,7 +137,6 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : setName( tr( "Default preset" ) ); - } From f9eb128b4620e17115472883a24efc50b7707f38 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 13:39:35 +0000 Subject: [PATCH 43/59] Proposed fix for 1692 Missing CLI option for rendering --- src/core/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/main.cpp b/src/core/main.cpp index 2502058c2..dd129a096 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -191,6 +191,7 @@ int main( int argc, char * * argv ) "-x, --oversampling specify oversampling\n" " possible values: 1, 2, 4, 8\n" " default: 2\n" + "-32, --float 32bit float bit depth\n" "-u, --upgrade [out] upgrade file and save as \n" " standard out is used if no output file is specifed\n" "-d, --dump dump XML of compressed file \n" @@ -296,6 +297,12 @@ int main( int argc, char * * argv ) } ++i; } + else if ( argc > i && + ( QString( argv[i] ) =="--float") || + QString( argv[i] ) == "-32" ) + { + os.depth = ProjectRenderer::Depth_32Bit; + } else if( argc > i && ( QString( argv[i] ) == "--interpolation" || QString( argv[i] ) == "-i" ) ) From ad1dc2268f33981c00b4ee9f518724c57d269b34 Mon Sep 17 00:00:00 2001 From: SecondFlight Date: Wed, 28 Jan 2015 09:46:26 -0500 Subject: [PATCH 44/59] Changed the license to CC (BY) Seems more reasonable based on the discussion. --- data/projects/CoolSongs/LICENSES.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/projects/CoolSongs/LICENSES.TXT b/data/projects/CoolSongs/LICENSES.TXT index 17747f0a9..513efd613 100644 --- a/data/projects/CoolSongs/LICENSES.TXT +++ b/data/projects/CoolSongs/LICENSES.TXT @@ -15,7 +15,7 @@ - http://lmms.io/lsp/index.php?action=show&file=1327 * Greippi - Krem Kaakkuja (Second Flight Remix) - - CC (by-nd) + - CC (by) - http://lmms.io/lsp/index.php?action=show&file=6337 * Greippi-ardudar.mmpz From dd80301cee59805ca70bd23607c937aa744f9f33 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 15:35:01 +0000 Subject: [PATCH 45/59] Proposed fix for #1532 Tracks in song editor cannot be moved in pattern select mode. --- src/core/Track.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 426676f0e..80f30f4c1 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -2612,7 +2612,11 @@ void TrackView::mousePressEvent( QMouseEvent * _me ) } - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && _me->x() > widgetTotal ) { QWidget::mousePressEvent( _me ); } @@ -2666,8 +2670,11 @@ void TrackView::mousePressEvent( QMouseEvent * _me ) */ void TrackView::mouseMoveEvent( QMouseEvent * _me ) { - - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && _me->x() > widgetTotal ) { QWidget::mouseMoveEvent( _me ); } From 406bc40ddd3c9a069d93671712ee82d350a0ad07 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 17:06:19 +0000 Subject: [PATCH 46/59] fix 1692 reformat conditional statement to be consistant --- src/core/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/main.cpp b/src/core/main.cpp index dd129a096..6bdd1e3c9 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -298,8 +298,8 @@ int main( int argc, char * * argv ) ++i; } else if ( argc > i && - ( QString( argv[i] ) =="--float") || - QString( argv[i] ) == "-32" ) + ( QString( argv[i] ) =="--float" || + QString( argv[i] ) == "-32" ) ) { os.depth = ProjectRenderer::Depth_32Bit; } From fa6dd6da8b559b61f57e2f304f37fd3b4a70b905 Mon Sep 17 00:00:00 2001 From: Dave French Date: Wed, 28 Jan 2015 22:12:59 +0000 Subject: [PATCH 47/59] Change color of muted activity indicator from red to grey --- src/tracks/InstrumentTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 6d5a3056d..f6168801d 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -554,7 +554,7 @@ void InstrumentTrack::muteHasChanged() { if( m_mutedModel.value() ) { - m_fb->setActiveColor( QColor( "red" ) ); + m_fb->setActiveColor( QColor( 0x282828 ) ); } else { m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, From c02f043b3f5e64ef4b67a76b5e4be5c8844ad6a2 Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 29 Jan 2015 00:27:30 +0000 Subject: [PATCH 48/59] Changed color of InstrumentTrack activity indicators mute color to use the color defined in style.css as highlight --- src/tracks/InstrumentTrack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index f6168801d..fc2035669 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -554,7 +554,8 @@ void InstrumentTrack::muteHasChanged() { if( m_mutedModel.value() ) { - m_fb->setActiveColor( QColor( 0x282828 ) ); + m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::Highlight ) ); } else { m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, From dae0c05061e904bda042d783ac9da6c0b3002bf8 Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Wed, 28 Jan 2015 23:22:29 -0200 Subject: [PATCH 49/59] Change Shift+Resize selected notes on Piano Roll Selected notes: when resized would offset posterior, non-selected notes to mantain some kind of melodic structure. This is referred to as *sticky* behaviour. It also assumes some kind of intention that may not be the case. Also adds complexity to a simple feature. This commit makes only the the selected notes be offset. It also adds a new shortcut to the old behaviour . Fixes #1666 --- include/PianoRoll.h | 2 +- src/gui/editors/PianoRoll.cpp | 39 +++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 6260eaa7e..f4f313174 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -231,7 +231,7 @@ private: inline int noteEditRight() const; inline int noteEditLeft() const; - void dragNotes( int x, int y, bool alt, bool shift ); + void dragNotes( int x, int y, bool alt, bool shift, bool ctrl ); static const int cm_scrollAmtHoriz = 10; static const int cm_scrollAmtVert = 1; diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 0d3540975..c14b6b930 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -949,7 +949,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -981,7 +982,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -1022,7 +1024,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1063,7 +1066,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1120,7 +1124,11 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) } case Qt::Key_Control: - if ( isActiveWindow() ) + // Enter selection mode if: + // -> this window is active + // -> shift is not pressed + // ( is shortcut for sticky note resize) + if ( !( ke->modifiers() & Qt::ShiftModifier ) && isActiveWindow() ) { m_ctrlMode = m_editMode; m_editMode = ModeSelect; @@ -1265,7 +1273,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) return; } - // if holding control, go to selection mode + // if holding control, go to selection mode unless shift is also pressed if( me->modifiers() & Qt::ControlModifier && m_editMode != ModeSelect ) { m_ctrlMode = m_editMode; @@ -1991,12 +1999,10 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) pauseTestNotes(); } - dragNotes( - me->x(), - me->y(), + dragNotes( me->x(), me->y(), me->modifiers() & Qt::AltModifier, - me->modifiers() & Qt::ShiftModifier - ); + me->modifiers() & Qt::ShiftModifier, + me->modifiers() & Qt::ControlModifier ); if( replay_note && m_action == ActionMoveNote && ! ( ( me->modifiers() & Qt::ShiftModifier ) && ! m_startedWithShift ) ) { @@ -2408,7 +2414,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) -void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) +void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) { // dragging one or more notes around @@ -2458,9 +2464,12 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) { Note *note = *it; const int pos = note->pos().getTicks(); - // when resizing a note and holding shift: shift the following - // notes to preserve the melody - if( m_action == ActionResizeNote && shift ) + + // When resizing notes: + // If shift is pressed we resize and rearrange only the selected notes + // If shift + ctrl then we also rearrange all posterior notes (sticky) + if( m_action == ActionResizeNote && shift && + ( note->selected() || ctrl ) ) { int shifted_pos = note->oldPos().getTicks() + shift_offset; if( shifted_pos && pos == shift_ref_pos ) From 968d0215dfebf05563abb340becff3507c329712 Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 29 Jan 2015 09:49:20 +0000 Subject: [PATCH 50/59] Moved Setting of activity indicator color from InstrumentTrack to InstrumentTrackView --- include/InstrumentTrack.h | 2 +- src/tracks/InstrumentTrack.cpp | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index 85a19c3de..de5671514 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -225,7 +225,6 @@ protected slots: void updateBaseNote(); void updatePitch(); void updatePitchRange(); - void muteHasChanged(); private: @@ -321,6 +320,7 @@ private slots: void midiInSelected(); void midiOutSelected(); void midiConfigChanged(); + void muteHasChanged(); private: diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index fc2035669..5302658bd 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -124,7 +124,6 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : connect( &m_baseNoteModel, SIGNAL( dataChanged() ), this, SLOT( updateBaseNote() ) ); connect( &m_pitchModel, SIGNAL( dataChanged() ), this, SLOT( updatePitch() ) ); connect( &m_pitchRangeModel, SIGNAL( dataChanged() ), this, SLOT( updatePitchRange() ) ); - connect( &m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteHasChanged() ) ); m_effectChannelModel.setRange( 0, Engine::fxMixer()->numChannels()-1, 1); @@ -550,20 +549,6 @@ void InstrumentTrack::updatePitchRange() processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerDataEntry, midiPitchRange() ) ); } -void InstrumentTrack::muteHasChanged() -{ - if( m_mutedModel.value() ) - { - m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, - QPalette::Highlight ) ); - } else - { - m_fb->setActiveColor( QApplication::palette().color( QPalette::Active, - QPalette::BrightText ) ); - } - -} - @@ -941,6 +926,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV connect( m_activityIndicator, SIGNAL( released() ), this, SLOT( activityIndicatorReleased() ) ); _it->setIndicator( m_activityIndicator ); + connect( &_it->m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteHasChanged() ) ); setModel( _it ); } @@ -1145,6 +1131,22 @@ void InstrumentTrackView::midiConfigChanged() +void InstrumentTrackView::muteHasChanged() +{ + if(model()->m_mutedModel.value() ) + { + m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::Highlight ) ); + } else + { + m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::BrightText ) ); + } +} + + + + class fxLineLcdSpinBox : public LcdSpinBox From 5ce1bd874dcc6b09f5a60040f37c07c7eae7d400 Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 29 Jan 2015 10:13:25 +0000 Subject: [PATCH 51/59] renamed muteHasChanged to muteChanged in InstrumentTrackView --- include/InstrumentTrack.h | 2 +- src/tracks/InstrumentTrack.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index de5671514..ffbb61ccc 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -320,7 +320,7 @@ private slots: void midiInSelected(); void midiOutSelected(); void midiConfigChanged(); - void muteHasChanged(); + void muteChanged(); private: diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 5302658bd..e9317dc52 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -926,7 +926,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV connect( m_activityIndicator, SIGNAL( released() ), this, SLOT( activityIndicatorReleased() ) ); _it->setIndicator( m_activityIndicator ); - connect( &_it->m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteHasChanged() ) ); + connect( &_it->m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteChanged() ) ); setModel( _it ); } @@ -1131,7 +1131,7 @@ void InstrumentTrackView::midiConfigChanged() -void InstrumentTrackView::muteHasChanged() +void InstrumentTrackView::muteChanged() { if(model()->m_mutedModel.value() ) { From efa75b0151377e8ce6d13d5bdb79cbff86236c7f Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 29 Jan 2015 10:38:19 +0000 Subject: [PATCH 52/59] Checks for .mpt extension, before adding extension when saving project templates --- src/gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index b40674551..b8ddd6071 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -831,7 +831,7 @@ bool MainWindow::saveProjectAs() !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" ) { QString fname = sfd.selectedFiles()[0] ; - if( sfd.selectedNameFilter().contains( "(*.mpt)" ) ) + if( sfd.selectedNameFilter().contains( "(*.mpt)" ) && !sfd.selectedFiles()[0].endsWith( ".mpt" ) ) { fname += ".mpt"; } From 1ebbe31fae4bec778c56cfe5e4a1396d97b0d457 Mon Sep 17 00:00:00 2001 From: Dave French Date: Thu, 29 Jan 2015 11:36:21 +0000 Subject: [PATCH 53/59] Changed commandline flag to render in 32bit float from -32 to -a --- src/core/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/main.cpp b/src/core/main.cpp index 6bdd1e3c9..a489323fb 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -191,7 +191,7 @@ int main( int argc, char * * argv ) "-x, --oversampling specify oversampling\n" " possible values: 1, 2, 4, 8\n" " default: 2\n" - "-32, --float 32bit float bit depth\n" + "-a, --float 32bit float bit depth\n" "-u, --upgrade [out] upgrade file and save as \n" " standard out is used if no output file is specifed\n" "-d, --dump dump XML of compressed file \n" @@ -299,7 +299,7 @@ int main( int argc, char * * argv ) } else if ( argc > i && ( QString( argv[i] ) =="--float" || - QString( argv[i] ) == "-32" ) ) + QString( argv[i] ) == "-a" ) ) { os.depth = ProjectRenderer::Depth_32Bit; } From 27762a94378b690282c22f380d201dccfb6a2aa2 Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Thu, 29 Jan 2015 20:04:30 -0200 Subject: [PATCH 54/59] Fix Shift+Resize for single note should be sticky --- src/gui/editors/PianoRoll.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index c14b6b930..92f7f0f1e 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -2460,6 +2460,8 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // will be our iterator in the following loop NoteVector::ConstIterator it = notes.begin(); + + int sNotes = selectionCount(); while( it != notes.end() ) { Note *note = *it; @@ -2468,8 +2470,9 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // When resizing notes: // If shift is pressed we resize and rearrange only the selected notes // If shift + ctrl then we also rearrange all posterior notes (sticky) + // If shift is pressed but only one note is selected, apply sticky if( m_action == ActionResizeNote && shift && - ( note->selected() || ctrl ) ) + ( note->selected() || ctrl || sNotes == 1 ) ) { int shifted_pos = note->oldPos().getTicks() + shift_offset; if( shifted_pos && pos == shift_ref_pos ) From b1f0dd309992e50b894a5730b589e2e409775bfe Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 30 Jan 2015 08:39:11 +0100 Subject: [PATCH 55/59] ljud fil -> ljudfil & dialogvisas -> dialog visas --- data/locale/sv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 9950aed37..c4cd327a7 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -131,7 +131,7 @@ If you're interested in translating LMMS in another language or want to imp Click here, if you want to open another audio-file. A dialog will appear where you can select your file. Settings like looping-mode, start and end-points, amplify-value, and so on are not reset. So, it may not sound like the original sample. - Klicka här för att öppna en anna ljud fil. En dialogvisas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. + Klicka här för att öppna en annan ljudfil. En dialog visas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. Reverse sample From fc11a09b0b80fad699af513217732f12634dbfd4 Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 30 Jan 2015 10:38:16 +0100 Subject: [PATCH 56/59] Update Automation translations --- data/locale/sv.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index c4cd327a7..12242012c 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -9,7 +9,7 @@ Version %1 (%2/%3, Qt %4, %5) - + Version %1 (%2/%3, Qt %4, %5) About @@ -21,7 +21,7 @@ Authors - Utvecklare + Medverkande Translation @@ -316,7 +316,7 @@ If you're interested in translating LMMS in another language or want to imp Remove song-global automation - Ta bort gloabal automation + Ta bort global automation Remove all linked controls @@ -327,7 +327,7 @@ If you're interested in translating LMMS in another language or want to imp AutomationEditor Please open an automation pattern with the context menu of a control! - Öppna ett mönster ifrån en kontrollers kontext meny! + Öppna ett automationsmönster ifrån en kontrollers kontext meny! Values copied @@ -450,7 +450,7 @@ If you're interested in translating LMMS in another language or want to imp Automation Editor - no pattern - Redigera Automation - inget mönster + Redigera Automation - inget automationsmönster Automation Editor - %1 @@ -472,11 +472,11 @@ If you're interested in translating LMMS in another language or want to imp AutomationPatternView double-click to open this pattern in automation editor - dubbelklicka för att öppna det här mönstret för redigering + dubbelklicka för att öppna det här automationsmönstret för redigering Open in Automation editor - Öppna för att redigera + Öppna för att redigera automationsmönster Clear @@ -515,7 +515,7 @@ If you're interested in translating LMMS in another language or want to imp AutomationTrack Automation track - Automation spår + Automationsspår @@ -546,7 +546,7 @@ If you're interested in translating LMMS in another language or want to imp Add automation-track - Lägg till automationsmönster + Lägg till automationsspår Remove steps From 06cb85b771cc9936279ce330b60caa1a774f3bd2 Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Wed, 14 Jan 2015 16:46:36 -0200 Subject: [PATCH 57/59] Move FX assignment/creation logic to InsTrackView --- include/InstrumentTrack.h | 8 ++++++++ include/Track.h | 2 -- src/core/Track.cpp | 27 ++------------------------- src/tracks/InstrumentTrack.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index ffbb61ccc..f172e6094 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -322,6 +322,9 @@ private slots: void midiConfigChanged(); void muteChanged(); + void assignFxLine( int channelIndex ); + void createFxLine(); + private: InstrumentTrackWindow * m_window; @@ -375,6 +378,11 @@ public: void setInstrumentTrackView( InstrumentTrackView * _tv ); + InstrumentTrackView * instrumentTrackView() + { + return m_itv; + } + PianoView * pianoView() { return m_pianoView; diff --git a/include/Track.h b/include/Track.h index b766b6056..91aadfde2 100644 --- a/include/Track.h +++ b/include/Track.h @@ -391,8 +391,6 @@ private slots: void recordingOn(); void recordingOff(); void clearTrack(); - void assignFxLine( int channelIndex ); - void createFxLine(); private: static QPixmap * s_grip; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index a6f98e1df..524bc3837 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1711,29 +1711,6 @@ void TrackOperationsWidget::clearTrack() -/*! \brief Create and assign a new FX Channel for this track */ -void TrackOperationsWidget::createFxLine() -{ - int channelIndex = gui->fxMixerView()->addNewChannel(); - - Engine::fxMixer()->effectChannel( channelIndex )->m_name = m_trackView->getTrack()->name(); - - assignFxLine(channelIndex); -} - - - -/*! \brief Assign a specific FX Channel for this track */ -void TrackOperationsWidget::assignFxLine(int channelIndex) -{ - Track * track = m_trackView->getTrack(); - dynamic_cast( track )->effectChannelModel()->setValue( channelIndex ); - - gui->fxMixerView()->setCurrentFxLine( channelIndex ); -} - - - /*! \brief Remove this track from the track list * */ @@ -1777,7 +1754,7 @@ void TrackOperationsWidget::updateMenu() QMenu * fxMenu = new QMenu( tr( "FX %1: %2" ).arg( channelIndex ).arg( fxChannel->m_name ), to_menu ); QSignalMapper * fxMenuSignalMapper = new QSignalMapper(this); - fxMenu->addAction("Assign to new FX Channel" , this, SLOT( createFxLine() ) ); + fxMenu->addAction( tr( "Assign to new FX Channel" ), trackView, SLOT( createFxLine() ) ); fxMenu->addSeparator(); @@ -1794,7 +1771,7 @@ void TrackOperationsWidget::updateMenu() } to_menu->addMenu(fxMenu); - connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); + connect(fxMenuSignalMapper, SIGNAL(mapped(int)), trackView, SLOT(assignFxLine(int))); to_menu->addSeparator(); to_menu->addMenu( trackView->midiMenu() ); diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index e9317dc52..a4bef2828 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -963,6 +963,30 @@ InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() + +/*! \brief Create and assign a new FX Channel for this track */ +void InstrumentTrackView::createFxLine() +{ + int channelIndex = gui->fxMixerView()->addNewChannel(); + + Engine::fxMixer()->effectChannel( channelIndex )->m_name = getTrack()->name(); + + assignFxLine(channelIndex); +} + + + + +/*! \brief Assign a specific FX Channel for this track */ +void InstrumentTrackView::assignFxLine(int channelIndex) +{ + model()->effectChannelModel()->setValue( channelIndex ); + + gui->fxMixerView()->setCurrentFxLine( channelIndex ); +} + + + // TODO: Add windows to free list on freeInstrumentTrackWindow. // But, don't NULL m_window or disconnect signals. This will allow windows // that are being show/hidden frequently to stay connected. From c99e47f5816e802c45d8887be4684333ade2fb44 Mon Sep 17 00:00:00 2001 From: Amadeus Folego Date: Wed, 14 Jan 2015 16:50:25 -0200 Subject: [PATCH 58/59] Add "Assign to new FX Channel" action to FXSpinBox Fix #604 #921 --- include/InstrumentTrack.h | 6 +++- src/core/Track.cpp | 25 +------------- src/tracks/InstrumentTrack.cpp | 63 ++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index f172e6094..8c8c963fa 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -306,6 +306,9 @@ public: static void cleanupWindowCache(); + // Create a menu for assigning/creating channels for this track + QMenu * createFxMenu( QString title, QString newFxLabel ); + protected: virtual void dragEnterEvent( QDragEnterEvent * _dee ); @@ -378,11 +381,12 @@ public: void setInstrumentTrackView( InstrumentTrackView * _tv ); - InstrumentTrackView * instrumentTrackView() + InstrumentTrackView *instrumentTrackView() { return m_itv; } + PianoView * pianoView() { return m_pianoView; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 524bc3837..1eb16776d 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1747,31 +1747,8 @@ void TrackOperationsWidget::updateMenu() } if( InstrumentTrackView * trackView = dynamic_cast( m_trackView ) ) { - int channelIndex = trackView->model()->effectChannelModel()->value(); - - FxChannel * fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); - - QMenu * fxMenu = new QMenu( tr( "FX %1: %2" ).arg( channelIndex ).arg( fxChannel->m_name ), to_menu ); - QSignalMapper * fxMenuSignalMapper = new QSignalMapper(this); - - fxMenu->addAction( tr( "Assign to new FX Channel" ), trackView, SLOT( createFxLine() ) ); - fxMenu->addSeparator(); - - - for (int i = 0; i < Engine::fxMixer()->fxChannels().size(); ++i) - { - FxChannel * currentChannel = Engine::fxMixer()->fxChannels()[i]; - - if ( currentChannel != fxChannel ) - { - QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); - QAction * action = fxMenu->addAction( label, fxMenuSignalMapper, SLOT( map() ) ); - fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); - } - } - + QMenu *fxMenu = trackView->createFxMenu( tr( "FX %1: %2" ), tr( "Assign to new FX Channel" )); to_menu->addMenu(fxMenu); - connect(fxMenuSignalMapper, SIGNAL(mapped(int)), trackView, SLOT(assignFxLine(int))); to_menu->addSeparator(); to_menu->addMenu( trackView->midiMenu() ); diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index a4bef2828..7fcf2b0dc 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -36,12 +36,14 @@ #include #include #include +#include #include "FileDialog.h" #include "InstrumentTrack.h" #include "AudioPort.h" #include "AutomationPattern.h" #include "BBTrack.h" +#include "CaptionMenu.h" #include "ConfigManager.h" #include "ControllerConnection.h" #include "debug.h" @@ -1171,6 +1173,43 @@ void InstrumentTrackView::muteChanged() +QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) +{ + int channelIndex = model()->effectChannelModel()->value(); + + FxChannel *fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); + + // If title allows interpolation, pass channel index and name + if ( title.contains( "%2" ) ) + { + title = title.arg( channelIndex ).arg( fxChannel->m_name ); + } + + QMenu *fxMenu = new QMenu( title ); + + QSignalMapper * fxMenuSignalMapper = new QSignalMapper(fxMenu); + + fxMenu->addAction( newFxLabel, this, SLOT( createFxLine() ) ); + fxMenu->addSeparator(); + + for (int i = 0; i < Engine::fxMixer()->fxChannels().size(); ++i) + { + FxChannel * currentChannel = Engine::fxMixer()->fxChannels()[i]; + + if ( currentChannel != fxChannel ) + { + QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); + QAction * action = fxMenu->addAction( label, fxMenuSignalMapper, SLOT( map() ) ); + fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); + } + } + + connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); + + return fxMenu; +} + + class fxLineLcdSpinBox : public LcdSpinBox @@ -1189,6 +1228,30 @@ class fxLineLcdSpinBox : public LcdSpinBox gui->fxMixerView()->setFocus();// set focus to fxMixer window //engine::getFxMixerView()->raise(); } + + virtual void contextMenuEvent( QContextMenuEvent* event ) + { + // for the case, the user clicked right while pressing left mouse- + // button, the context-menu appears while mouse-cursor is still hidden + // and it isn't shown again until user does something which causes + // an QApplication::restoreOverrideCursor()-call... + mouseReleaseEvent( NULL ); + + QPointer contextMenu = new CaptionMenu( model()->displayName(), this ); + + // This condition is here just as a safety check, fxLineLcdSpinBox is aways + // created inside a TabWidget inside an InstrumentTrackWindow + if ( InstrumentTrackWindow* window = dynamic_cast( (QWidget *)this->parent()->parent() ) ) + { + QMenu *fxMenu = window->instrumentTrackView()->createFxMenu( tr( "Assign to:" ), tr( "New FX Channel" ) ); + contextMenu->addMenu( fxMenu ); + + contextMenu->addSeparator(); + } + addDefaultActions( contextMenu ); + contextMenu->exec( QCursor::pos() ); + } + }; From 5504b3fe9c3dad464fdbd1ed1fb9c304fadc00ee Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 30 Jan 2015 18:54:32 +0100 Subject: [PATCH 59/59] Remove ' type="unfinished" ' on translated strings Also miscellaneous fixes. --- data/locale/sv.ts | 342 +++++++++++++++++++++++----------------------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 12242012c..85198a1eb 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -5,27 +5,27 @@ AboutDialog About LMMS - Om LMMS + Om LMMS Version %1 (%2/%3, Qt %4, %5) - Version %1 (%2/%3, Qt %4, %5) + Version %1 (%2/%3, Qt %4, %5) About - Om + Om LMMS - easy music production for everyone - LMMS - enkel musikproduktion för alla + LMMS - enkel musikproduktion för alla Authors - Medverkande + Medverkande Translation - Översättning + Översättning Current language not translated (or native English). @@ -35,11 +35,11 @@ If you're interested in translating LMMS in another language or want to imp License - Licens + Licens Copyright (c) 2004-2014, LMMS developers - Copyright (c) 2004-2014, LMMS utvecklare + Copyright (c) 2004-2014, LMMS utvecklare <html><head/><body><p><a href="http://lmms.io"><span style=" text-decoration: underline; color:#0000ff;">http://lmms.io</span></a></p></body></html> @@ -47,26 +47,26 @@ If you're interested in translating LMMS in another language or want to imp LMMS - LMMS + LMMS Involved - Involverad + Involverad Contributors ordered by number of commits: - Medverkande, ordnade efter mängd bidrag: + Medverkande, ordnade efter mängd bidrag: AmplifierControlDialog VOL - VOL + VOL Volume: - Volym: + Volym: PAN @@ -78,26 +78,26 @@ If you're interested in translating LMMS in another language or want to imp LEFT - VÄNSTER + VÄNSTER Left gain: - Vänster förstärkning: + Vänster förstärkning: RIGHT - HÖGER + HÖGER Right gain: - Höger förstärkning: + Höger förstärkning: AmplifierControls Volume - Volym + Volym Panning @@ -105,571 +105,571 @@ If you're interested in translating LMMS in another language or want to imp Left gain - Vänster förstärkning + Vänster förstärkning Right gain - Höger förstärkning + Höger förstärkning AudioAlsa::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioFileProcessorView Open other sample - Oppna annan ljudfil + Oppna annan ljudfil Click here, if you want to open another audio-file. A dialog will appear where you can select your file. Settings like looping-mode, start and end-points, amplify-value, and so on are not reset. So, it may not sound like the original sample. - Klicka här för att öppna en annan ljudfil. En dialog visas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. + Klicka här för att öppna en annan ljudfil. En dialog visas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. Reverse sample - Spela baklänges + Spela baklänges If you enable this button, the whole sample is reversed. This is useful for cool effects, e.g. a reversed crash. - Den här knappen gör att ljudfilen spelas baklänges. Den kan användas för intressanta effeker t.ex. en baklänges cymbal. + Den här knappen gör att ljudfilen spelas baklänges. Den kan användas för intressanta effeker t.ex. en baklänges cymbal. Amplify: - Förstärkning: + Förstärkning: With this knob you can set the amplify ratio. When you set a value of 100% your sample isn't changed. Otherwise it will be amplified up or down (your actual sample-file isn't touched!) - Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men originalfilen förändras inte. + Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men originalfilen förändras inte. Startpoint: - Startpunkt: + Startpunkt: Endpoint: - Slutpunkt: + Slutpunkt: Continue sample playback across notes - Forsätt spela ljudfil över noter + Forsätt spela ljudfil över noter Enabling this option makes the sample continue playing across different notes - if you change pitch, or the note length stops before the end of the sample, then the next note played will continue where it left off. To reset the playback to the start of the sample, insert a note at the bottom of the keyboard (< 20 Hz) - Denna inställningen gör att ljudfilen förtsätter spela över noter. Om en not avslutas före ljudfilen är slut fortsätter nästa not där den förra slutade. Om du vill starta från början av ljudfilen innan den spelat färdigt, placera en not på botten av pianot (vid 20Hz) + Denna inställningen gör att ljudfilen förtsätter spela över noter. Om en not avslutas före ljudfilen är slut fortsätter nästa not där den förra slutade. Om du vill starta från början av ljudfilen innan den spelat färdigt, placera en not på botten av pianot (vid 20Hz) Disable loop - Avaktivera looping + Avaktivera looping This button disables looping. The sample plays only once from start to end. - Den här knappen avaktiverar looping.Ljudfilen spelas bara en gång från starttill slut. + Den här knappen avaktiverar looping. Ljudfilen spelas bara en gång från start till slut. Enable loop - Aktivera looping + Aktivera looping This button enables forwards-looping. The sample loops between the end point and the loop point. - Den här knappen aktiverar looping. Ljudfilen loopar mellan slutpunkten och looppunkten. + Den här knappen aktiverar looping. Ljudfilen loopar mellan slutpunkten och looppunkten. This button enables ping-pong-looping. The sample loops backwards and forwards between the end point and the loop point. - Den här knappen aktiverar "ping-pong" looping. Ljudfilen spelar från start till slut, och sen tilbaks, och fortsäter så. + Den här knappen aktiverar "ping-pong" looping. Ljudfilen spelar från start till slut, och sen tilbaks, och fortsäter så. With this knob you can set the point where AudioFileProcessor should begin playing your sample. - Med den här vreden ställer du in vartifrån ljudfilen ska börja spela. + Med den här vreden ställer du in vartifrån ljudfilen ska börja spela. With this knob you can set the point where AudioFileProcessor should stop playing your sample. - Med den här vreden ställer du in vart ljudfilen slutar spela. + Med den här vreden ställer du in vart ljudfilen slutar spela. Loopback point: - Loopback punkt: + Loopback punkt: With this knob you can set the point where the loop starts. - Den här vreden ställer in vart loopen startar. + Den här vreden ställer in vart loopen startar. AudioFileProcessorWaveView Sample length: - Ljudfilens lengd: + Ljudfilens längd: AudioJack JACK client restarted - JACK klienten omstartades + JACK klienten omstartades LMMS was kicked by JACK for some reason. Therefore the JACK backend of LMMS has been restarted. You will have to make manual connections again. - LMMS blev bortkopplat från JACK. LMMS JACK backend omstartades därfor. Du får manuellt koppla om igen. + LMMS blev bortkopplat från JACK. LMMS JACK backend omstartades därfor. Du får manuellt koppla om igen. JACK server down - JACK server nerstängd + JACK server nerstängd The JACK server seems to have been shutdown and starting a new instance failed. Therefore LMMS is unable to proceed. You should save your project and restart JACK and LMMS. - JACK servern stängde av och det gick inte starta en ny. LMMS kan inte fortsätta. Du bör spara ditt projekt och starta om både JACK och LMMS. + JACK servern stängde av och det gick inte starta en ny. LMMS kan inte fortsätta. Du bör spara ditt projekt och starta om både JACK och LMMS. CLIENT-NAME - KLIENT-NAMN + KLIENT-NAMN CHANNELS - KANALER + KANALER AudioOss::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioPortAudio::setupWidget BACKEND - BACKEND + BACKEND DEVICE - ENHET + ENHET AudioPulseAudio::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioSdl::setupWidget DEVICE - ENHET + ENHET AutomatableModel &Reset (%1%2) - &Nollställ (%1%2) + &Nollställ (%1%2) &Copy value (%1%2) - Kopiera värder (%1%2) + Kopiera värde (%1%2) &Paste value (%1%2) - &Klistra in värde (%1%2) + &Klistra in värde (%1%2) Edit song-global automation - Redigera global automation + Redigera global automation Connected to %1 - Kopplad till %1 + Kopplad till %1 Connected to controller - Kopplad till controller + Kopplad till controller Edit connection... - Redigera koppling... + Redigera koppling... Remove connection - Ta bort koppling + Ta bort koppling Connect to controller... - Koppla till kontroller... + Koppla till kontroller... Remove song-global automation - Ta bort global automation + Ta bort global automation Remove all linked controls - Ta bort alla kopplade kontroller + Ta bort alla kopplade kontroller AutomationEditor Please open an automation pattern with the context menu of a control! - Öppna ett automationsmönster ifrån en kontrollers kontext meny! + Öppna ett automationsmönster ifrån en kontrollers kontextmeny! Values copied - Värden kopierade + Värden kopierade All selected values were copied to the clipboard. - Alla valda värden blev kopierade till urklipp. + Alla valda värden blev kopierade till urklipp. AutomationEditorWindow Play/pause current pattern (Space) - Spela/pausa aktuellt mönster (mellanslag) + Spela/pausa aktuellt mönster (mellanslag) Click here if you want to play the current pattern. This is useful while editing it. The pattern is automatically looped when the end is reached. - Clicka här för att spela det aktuella mönstret. Det härär hjälpsamt närman redigerar. Mönstret spelas från början igen när de nått sitt slut. + Clicka här för att spela det aktuella mönstret. Det här är hjälpsamt när man redigerar. Mönstret spelas från början igen när de nått sitt slut. Stop playing of current pattern (Space) - Sluta spela aktuellt mönster (mellanslag) + Sluta spela aktuellt mönster (mellanslag) Click here if you want to stop playing of the current pattern. - Klicka här för att stoppa uppspelning av de aktuella mönstret. + Klicka här för att stoppa uppspelning av de aktuella mönstret. Draw mode (Shift+D) - Ritläge (Shift+D) + Ritläge (Shift+D) Erase mode (Shift+E) - Suddläge (Shift+E) + Suddläge (Shift+E) Flip vertically - Spegla vertikalt + Spegla vertikalt Flip horizontally - Spegla horizontellt + Spegla horizontellt Click here and the pattern will be inverted.The points are flipped in the y direction. - Klicka här för att spegla mönstret. Punkterna förflyttas på y-axeln + Klicka här för att spegla mönstret. Punkterna förflyttas på y-axeln Click here and the pattern will be reversed. The points are flipped in the x direction. - Klicka här för att spegla mönstret. Punkterna förflyttas på x-axeln + Klicka här för att spegla mönstret. Punkterna förflyttas på x-axeln Click here and draw-mode will be activated. In this mode you can add and move single values. This is the default mode which is used most of the time. You can also press 'Shift+D' on your keyboard to activate this mode. - Klicka här för att aktivera ritläget. I detta läget kan du lägga till och förflytta individuella värden. Det här är standardläget. Det går också att trycka 'Shift+D' på tangentborded för att aktivera detta läget. + Klicka här för att aktivera ritläget. I detta läget kan du lägga till och förflytta individuella värden. Det här är standardläget. Det går också att trycka 'Shift+D' på tangentborded för att aktivera detta läget. Click here and erase-mode will be activated. In this mode you can erase single values. You can also press 'Shift+E' on your keyboard to activate this mode. - Klicka här för att aktivera suddläget. I detta läget kan du ta bort individuella värden. Det går också att trycka 'Shift+E' på tangentborded för att aktivera detta läget. + Klicka här för att aktivera suddläget. I detta läget kan du ta bort individuella värden. Det går också att trycka 'Shift+E' på tangentborded för att aktivera detta läget. Discrete progression - Diskret talföljd + Diskret talföljd Linear progression - Linjär talföljd + Linjär talföljd Cubic Hermite progression - Cubic Hermite talföljd + Cubic Hermite talföljd Tension value for spline - Spänning i mönstrets spline + Spänning i mönstrets spline A higher tension value may make a smoother curve but overshoot some values. A low tension value will cause the slope of the curve to level off at each control point. - Högre spänning ger en mjuk kurva som ibland missar individuella punkter. Med lägre spänning planar kurvan ut nära punkterna. + Högre spänning ger en mjuk kurva som ibland missar individuella punkter. Med lägre spänning planar kurvan ut nära punkterna. Click here to choose discrete progressions for this automation pattern. The value of the connected object will remain constant between control points and be set immediately to the new value when each control point is reached. - Klicka här för att aktivera diskret talföljd. Värdet är konstant mella kontroll punkter och ändras direkt när en ny kontrollpunkt nås. + Klicka här för att aktivera diskret talföljd. Värdet är konstant mella kontroll punkter och ändras direkt när en ny kontrollpunkt nås. Click here to choose linear progressions for this automation pattern. The value of the connected object will change at a steady rate over time between control points to reach the correct value at each control point without a sudden change. - Klicka här för att aktivera linjär talföljd. Värdet ändras vid en stadig takt mellan kontrollpunkter för att gradvis nå nästa värde. + Klicka här för att aktivera linjär talföljd. Värdet ändras vid en stadig takt mellan kontrollpunkter för att gradvis nå nästa värde. Click here to choose cubic hermite progressions for this automation pattern. The value of the connected object will change in a smooth curve and ease in to the peaks and valleys. - Klicka här för att aktivera cubic hermite talföljd. Värdet följer en mjuk kurva mellan kontrollpunkter. + Klicka här för att aktivera cubic hermite talföljd. Värdet följer en mjuk kurva mellan kontrollpunkter. Cut selected values (Ctrl+X) - Klipp ut valda värden (ctrl+X) + Klipp ut valda värden (Ctrl+X) Copy selected values (Ctrl+C) - Kopiera valda värden (ctrl+C) + Kopiera valda värden (ctrl+C) Paste values from clipboard Ctrl+V) - Klistra värden (Ctrl+V) + Klistra värden (Ctrl+V) Click here and selected values will be cut into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - Klicka här för att klippa de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. + Klicka här för att klippa de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. Click here and selected values will be copied into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - Klicka här för att kopiera de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. + Klicka här för att kopiera de valda värderna. Du kan sedan klistra dem var som helst genom att klicka på klistra knappen. Click here and the values from the clipboard will be pasted at the first visible measure. - Klicka här för att klistra kopierade värderna vid den första synliga metern. + Klicka här för att klistra kopierade värderna vid den första synliga metern. Tension: - Spänning: + Spänning: Automation Editor - no pattern - Redigera Automation - inget automationsmönster + Redigera Automation - inget automationsmönster Automation Editor - %1 - Redigera Automation - %1 + Redigera Automation - %1 AutomationPattern Drag a control while pressing <Ctrl> - Dra en kontroll samtidigt som du håller <Ctrl> + Dra en kontroll samtidigt som du håller <Ctrl> Model is already connected to this pattern. - Modellen är redan kopplad till detta mönstret. + Modellen är redan kopplad till detta mönstret. AutomationPatternView double-click to open this pattern in automation editor - dubbelklicka för att öppna det här automationsmönstret för redigering + dubbelklicka för att öppna det här automationsmönstret för redigering Open in Automation editor - Öppna för att redigera automationsmönster + Redigera automationsmönster Clear - Rensa + Rensa Reset name - Nollställ namn + Nollställ namn Change name - Byt namn + Byt namn %1 Connections - %1 Kopplingar + %1 Kopplingar Disconnect "%1" - Avkoppla "%1" + Avkoppla "%1" Set/clear record - Set/rensa inspelning + Flip Vertically (Visible) - Spegla Vertikalt (Synligt) + Spegla Vertikalt (Synligt) Flip Horizontally (Visible) - Spegla Horizontellt (Synligt) + Spegla Horizontellt (Synligt) AutomationTrack Automation track - Automationsspår + Automationsspår BBEditor Beat+Bassline Editor - Redigera Trummor+Bas + Redigera Trummor+Bas Play/pause current beat/bassline (Space) - Spela/pause Trummor+Bas + Spela/pause Trummor+Bas Stop playback of current beat/bassline (Space) - Avsluta uppspelning av Trummor+Bas + Avsluta uppspelning av trummor/bas Click here to play the current beat/bassline. The beat/bassline is automatically looped when its end is reached. - Klicka här för att spela Trummor/Bas.Mönstret loopar när det nåt sitt slut. + Klicka här för att spela trummor/bas. Mönstret loopar när det nåt sitt slut. Click here to stop playing of current beat/bassline. - Klicka här för att sluta spela trummor/bas. + Klicka här för att sluta spela trummor/bas. Add beat/bassline - Lägg till trummor/bas + Lägg till trummor/bas Add automation-track - Lägg till automationsspår + Lägg till automationsspår Remove steps - Ta bort steg + Ta bort steg Add steps - Lägg till steg + Lägg till steg BBTCOView Open in Beat+Bassline-Editor - Öppna för att redigera Trummor+Bas + Redigera Trummor+Bas Reset name - Nollställ namn + Nollställ namn Change name - Byt namn + Byt namn Change color - Byt färg + Byt färg Reset color to default - Byt färg till standard + Byt färg till standard BBTrack Beat/Bassline %1 - Trummor/Bas %1 + Trum/Basmönster %1 Clone of %1 - Kopia av %1 + Kopia av %1 BassBoosterControlDialog FREQ - FREQ + FREQ Frequency: - Frekven: + Frekvens: GAIN - VOL + FÖRST Gain: - Förstärkning: + Förstärkning: RATIO - RATIO + RATIO Ratio: - Ratio: + Ratio: BassBoosterControls Frequency - Frekvens + Frekvens Gain - Förstärkning + Förstärkning Ratio - Ratio + Ratio BitcrushControlDialog IN - IN + IN OUT - UT + UT GAIN - VOL + FÖRST Input Gain: - Input Förstärkning: + Input Förstärkning: NOIS - BRUS + Input Noise: - Input brus: + Output Gain: - Output Förstärkning + Output Förstärkning CLIP - CLIP + Output Clip: - Output Clip: + Rate @@ -709,22 +709,22 @@ If you're interested in translating LMMS in another language or want to imp Levels - Nivåer + Nivåer Levels: - Nivåer: + Nivåer: CaptionMenu &Help - &Hjälp + &Hjälp Help (not available) - Hjälp (inte tillgängligt) + Hjälp (inte tillgängligt) @@ -735,45 +735,45 @@ If you're interested in translating LMMS in another language or want to imp Click here to show or hide the graphical user interface (GUI) of Carla. - Klicka här för att öppna eller stänga Carlas GUI. + Controller Controller %1 - Kontroller %1 + Kontroller %1 ControllerConnectionDialog Connection Settings - Kopplingsinställningar + Kopplingsinställningar MIDI CONTROLLER - MIDI KONTROLLER + MIDI KONTROLLER Input channel - Input kanal + Inputkanal CHANNEL - KANAL + KANAL Input controller - Input kontroller + Inputkontroller CONTROLLER - KONTROLLER + KONTROLLER Auto Detect - Upptäck automatiskt + Upptäck Automatiskt MIDI-devices to receive MIDI-events from @@ -781,7 +781,7 @@ If you're interested in translating LMMS in another language or want to imp USER CONTROLLER - ANVÄNDARKONTROLLER + ANVÄNDARKONTROLLER MAPPING FUNCTION @@ -789,15 +789,15 @@ If you're interested in translating LMMS in another language or want to imp OK - OK + OK Cancel - Avbryt + Avbryt LMMS - + LMMS Cycle Detected. @@ -812,38 +812,38 @@ If you're interested in translating LMMS in another language or want to imp Add - Lägg till + Lägg till Confirm Delete - + Bekräfta Borttagning Confirm delete? There are existing connection(s) associted with this controller. There is no way to undo. - Vill du verkligen ta bort? Det finns kopplingar till den här kotrollen, och operationen går inte ångra. + Vill du verkligen ta bort? Det finns kopplingar till den här kontrollern, och operationen går inte ångra. ControllerView Controls - Kontroller + Kontroller Controllers are able to automate the value of a knob, slider, and other controls. - Kontroller kan automatisera värdet på en vred, reglage, och andra kontroller + Kontroller kan automatisera värdet på en vred, reglage, och andra kontroller Rename controller - Byt namn på kontroller + Byt namn på kontroller Enter the new name for this controller - Skriv nya namnet på kontrollern + Skriv nya namnet på kontrollern &Remove this plugin - &Ta bort denna pluginen + @@ -1124,7 +1124,7 @@ If you're interested in translating LMMS in another language or want to imp DummyEffect NOT FOUND - + HITTAS INTE