From 5674bb58e2554e3cfc9e01951de27a81c82f7c67 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 29 Jul 2023 09:58:40 +0200 Subject: [PATCH 01/27] Fix HiDPI issues for menus Menus now use the size that users have set globally for their applications. This is accomplished by removing the fixed font size definition (in points) for `QMenu` in `style.css`. In some places the menus had been set to hard coded font sizes. This code is also removed and applies to the following menus: * Combo box menus * Track operation widget (gear icon on tracks) * The MIDI port menu --- data/themes/default/style.css | 4 ---- src/gui/menus/MidiPortMenu.cpp | 1 - src/gui/tracks/TrackOperationsWidget.cpp | 1 - src/gui/widgets/ComboBox.cpp | 1 - 4 files changed, 7 deletions(-) diff --git a/data/themes/default/style.css b/data/themes/default/style.css index a9646cfe4..12b63cfec 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -115,7 +115,6 @@ QSplashScreen QLabel { QMenu { border-top: 2px solid #08993E; background-color: #15191c; - font-size: 11px; } QMenu::separator { @@ -133,15 +132,12 @@ QMenu::item { QMenu::item:selected { color: #d1d8e4; - font-weight: normal; background-color: #21272b; } QMenu::item:disabled { color: #515459; background-color: #262b30; - font-size: 12px; - font-weight: normal; padding: 4px 32px 4px 20px; } diff --git a/src/gui/menus/MidiPortMenu.cpp b/src/gui/menus/MidiPortMenu.cpp index b1ddf71c9..67ad01f87 100644 --- a/src/gui/menus/MidiPortMenu.cpp +++ b/src/gui/menus/MidiPortMenu.cpp @@ -34,7 +34,6 @@ MidiPortMenu::MidiPortMenu( MidiPort::Modes _mode ) : ModelView( nullptr, this ), m_mode( _mode ) { - setFont( pointSize<9>( font() ) ); connect( this, SIGNAL(triggered(QAction*)), this, SLOT(activatedPort(QAction*))); } diff --git a/src/gui/tracks/TrackOperationsWidget.cpp b/src/gui/tracks/TrackOperationsWidget.cpp index ddbd2eacd..3e3654974 100644 --- a/src/gui/tracks/TrackOperationsWidget.cpp +++ b/src/gui/tracks/TrackOperationsWidget.cpp @@ -64,7 +64,6 @@ TrackOperationsWidget::TrackOperationsWidget( TrackView * parent ) : "to begin a new drag'n'drop action." ).arg(UI_CTRL_KEY) ); auto toMenu = new QMenu(this); - toMenu->setFont( pointSize<9>( toMenu->font() ) ); connect( toMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu())); diff --git a/src/gui/widgets/ComboBox.cpp b/src/gui/widgets/ComboBox.cpp index bdf78ccce..2377a37ab 100644 --- a/src/gui/widgets/ComboBox.cpp +++ b/src/gui/widgets/ComboBox.cpp @@ -70,7 +70,6 @@ ComboBox::ComboBox( QWidget * _parent, const QString & _name ) : } setFont( pointSize<9>( font() ) ); - m_menu.setFont( pointSize<8>( m_menu.font() ) ); connect( &m_menu, SIGNAL(triggered(QAction*)), this, SLOT(setItem(QAction*))); From 67dcdf2c65a306933e2b34379a04c2cee85ed8ce Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 29 Jul 2023 10:19:47 +0200 Subject: [PATCH 02/27] Fix HiDPI issue of sample track window Fix one of the HiDPI issues of the sample track window by removing the hard coded font size of the name line edit. --- src/gui/SampleTrackWindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/SampleTrackWindow.cpp b/src/gui/SampleTrackWindow.cpp index 6fe70bf41..06afdfd3d 100644 --- a/src/gui/SampleTrackWindow.cpp +++ b/src/gui/SampleTrackWindow.cpp @@ -74,7 +74,6 @@ SampleTrackWindow::SampleTrackWindow(SampleTrackView * tv) : // setup line edit for changing sample track name m_nameLineEdit = new QLineEdit; - m_nameLineEdit->setFont(pointSize<9>(m_nameLineEdit->font())); connect(m_nameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); From 48cdaddd9dd1a9c1a3716995d752bed567b6c9ad Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 29 Jul 2023 16:21:05 +0200 Subject: [PATCH 03/27] HiDPI fixes for elements based on QTreeView Fix the HiDPI problems for elements that are based on QTreeView by removing the fixed point based font size from the style sheet. This affects: * The file browser * The headings of the plugin browser * The patch selection dialogs for GigPlayer and SoundFont player Also make the text size of the check boxes for user content and factory content based on a point size instead of a pixel size. --- data/themes/default/style.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/themes/default/style.css b/data/themes/default/style.css index a9646cfe4..52f60e4ed 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -9,7 +9,6 @@ QLabel, QTreeWidget, QListWidget, QGroupBox, QMenuBar { QTreeView { outline: none; - font-size: 12px; } QTreeWidget::item { @@ -42,7 +41,7 @@ QMdiArea { lmms--gui--FileBrowser QCheckBox { - font-size: 10px; + font-size: 8pt; color: white; } From d2a0780a6eca1fbddc7b3cd2dc050d283799883d Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 28 Aug 2023 20:12:09 +0200 Subject: [PATCH 04/27] Adjust classic style sheet Adjust the classic style sheet in the same way that the default style sheet was adjusted. The change also removes the usage of a bold font weight for selected menu items to achieve a more consistent feel. --- data/themes/classic/style.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 2880fe661..777dbc230 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -82,7 +82,6 @@ lmms--gui--TextFloat, lmms--gui--SimpleTextFloat { QMenu { border:1px solid #747474; background-color: #c9c9c9; - font-size:11px; } QMenu::separator { @@ -98,15 +97,12 @@ QMenu::item { QMenu::item:selected { color: white; - font-weight:bold; background-color: #747474; } QMenu::item:disabled { color: #747474; background-color: #c9c9c9; - font-size:12px; - font-weight: normal; padding: 4px 32px 4px 20px; } From a8d765f8d57075217546282a55d3bb407512f4bf Mon Sep 17 00:00:00 2001 From: MrTopom Date: Sun, 10 Sep 2023 17:52:18 +0200 Subject: [PATCH 05/27] Make files visible when searching in ``FileBrowser`` (#6845) * Change the title for SideBarWidgets to be vertically centered related to icon and with no underlining * Update src/gui/SideBarWidget.cpp Co-authored-by: saker * Updating FileBrowser display when searching : showing matching files * Correcting increment and removing duplicated calls * Correcting reload tree when filter is activated --------- Co-authored-by: saker --- include/FileBrowser.h | 9 ++- src/gui/FileBrowser.cpp | 124 ++++++++++++++++++++++++++++------------ 2 files changed, 95 insertions(+), 38 deletions(-) diff --git a/include/FileBrowser.h b/include/FileBrowser.h index 3334a73f6..eafb827da 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -75,8 +75,7 @@ public: private slots: void reloadTree(); void expandItems( QTreeWidgetItem * item=nullptr, QList expandedDirs = QList() ); - // call with item=NULL to filter the entire tree - bool filterItems( const QString & filter, QTreeWidgetItem * item=nullptr ); + bool filterAndExpandItems(const QString & filter, QTreeWidgetItem * item = nullptr); void giveFocusToFilter(); private: @@ -84,6 +83,9 @@ private: void addItems( const QString & path ); + void saveDirectoriesStates(); + void restoreDirectoriesStates(); + FileBrowserTreeWidget * m_fileBrowserTreeWidget; QLineEdit * m_filterEdit; @@ -99,6 +101,8 @@ private: QCheckBox* m_showFactoryContent = nullptr; QString m_userDir; QString m_factoryDir; + QList m_savedExpandedDirs; + QString m_previousFilterValue; } ; @@ -115,7 +119,6 @@ public: //! that are expanded in the tree. QList expandedDirs( QTreeWidgetItem * item = nullptr ) const; - protected: void contextMenuEvent( QContextMenuEvent * e ) override; void mousePressEvent( QMouseEvent * me ) override; diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index c0763d542..181e67cd7 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -23,7 +23,6 @@ * */ - #include #include #include @@ -126,7 +125,7 @@ FileBrowser::FileBrowser(const QString & directories, const QString & filter, m_filterEdit->setPlaceholderText( tr("Search") ); m_filterEdit->setClearButtonEnabled( true ); connect( m_filterEdit, SIGNAL( textEdited( const QString& ) ), - this, SLOT( filterItems( const QString& ) ) ); + this, SLOT( filterAndExpandItems( const QString& ) ) ); auto reload_btn = new QPushButton(embed::getIconPixmap("reload"), QString(), searchWidget); reload_btn->setToolTip( tr( "Refresh list" ) ); @@ -145,53 +144,95 @@ FileBrowser::FileBrowser(const QString & directories, const QString & filter, auto filterFocusShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this, SLOT(giveFocusToFilter())); filterFocusShortcut->setContext(Qt::WidgetWithChildrenShortcut); + m_previousFilterValue = ""; + reloadTree(); show(); } -bool FileBrowser::filterItems( const QString & filter, QTreeWidgetItem * item ) +void FileBrowser::saveDirectoriesStates() +{ + m_savedExpandedDirs = m_fileBrowserTreeWidget->expandedDirs(); +} + +void FileBrowser::restoreDirectoriesStates() { - // call with item=NULL to filter the entire tree + expandItems(nullptr, m_savedExpandedDirs); +} + +bool FileBrowser::filterAndExpandItems(const QString & filter, QTreeWidgetItem * item) +{ + // Call with item = nullptr to filter the entire tree + + if (item == nullptr) + { + // First search character so need to save current expanded directories + if (m_previousFilterValue.isEmpty()) + { + saveDirectoriesStates(); + } + + m_previousFilterValue = filter; + } + + if (filter.isEmpty()) + { + // Restore previous expanded directories + if (item == nullptr) + { + restoreDirectoriesStates(); + } + + return false; + } + bool anyMatched = false; int numChildren = item ? item->childCount() : m_fileBrowserTreeWidget->topLevelItemCount(); - for( int i = 0; i < numChildren; ++i ) + + for (int i = 0; i < numChildren; ++i) { QTreeWidgetItem * it = item ? item->child( i ) : m_fileBrowserTreeWidget->topLevelItem(i); - // is directory? - if( it->childCount() ) + auto d = dynamic_cast(it); + if (d) { - // matches filter? - if( it->text( 0 ). - contains( filter, Qt::CaseInsensitive ) ) + if (it->text(0).contains(filter, Qt::CaseInsensitive)) { - // yes, then show everything below - it->setHidden( false ); - filterItems( QString(), it ); + it->setHidden(false); + it->setExpanded(true); + filterAndExpandItems(QString(), it); anyMatched = true; } else { - // only show if item below matches filter - bool didMatch = filterItems( filter, it ); - it->setHidden( !didMatch ); + // Expanding is required when recursive to load in its contents, even if it's collapsed right afterward + it->setExpanded(true); + + bool didMatch = filterAndExpandItems(filter, it); + it->setHidden(!didMatch); + it->setExpanded(didMatch); anyMatched = anyMatched || didMatch; } } - // a standard item (i.e. no file or directory item?) - else if( it->type() == QTreeWidgetItem::Type ) - { - // hide if there's any filter - it->setHidden( !filter.isEmpty() ); - } + else { - // file matches filter? - bool didMatch = it->text( 0 ). - contains( filter, Qt::CaseInsensitive ); - it->setHidden( !didMatch ); - anyMatched = anyMatched || didMatch; + auto f = dynamic_cast(it); + if (f) + { + // File + bool didMatch = it->text(0).contains(filter, Qt::CaseInsensitive); + it->setHidden(!didMatch); + anyMatched = anyMatched || didMatch; + } + + // A standard item (i.e. no file or directory item?) + else + { + // Hide if there's any filter + it->setHidden(!filter.isEmpty()); + } } } @@ -201,15 +242,20 @@ bool FileBrowser::filterItems( const QString & filter, QTreeWidgetItem * item ) void FileBrowser::reloadTree() { - QList expandedDirs = m_fileBrowserTreeWidget->expandedDirs(); - const QString text = m_filterEdit->text(); - m_filterEdit->clear(); + if (m_filterEdit->text().isEmpty()) + { + saveDirectoriesStates(); + } + m_fileBrowserTreeWidget->clear(); + QStringList paths = m_directories.split('*'); + if (m_showUserContent && !m_showUserContent->isChecked()) { paths.removeAll(m_userDir); } + if (m_showFactoryContent && !m_showFactoryContent->isChecked()) { paths.removeAll(m_factoryDir); @@ -222,9 +268,15 @@ void FileBrowser::reloadTree() addItems(path); } } - expandItems(nullptr, expandedDirs); - m_filterEdit->setText( text ); - filterItems( text ); + + if (m_filterEdit->text().isEmpty()) + { + restoreDirectoriesStates(); + } + else + { + filterAndExpandItems(m_filterEdit->text()); + } } @@ -240,12 +292,16 @@ void FileBrowser::expandItems(QTreeWidgetItem* item, QList expandedDirs { // Expanding is required when recursive to load in its contents, even if it's collapsed right afterward if (m_recurse) { d->setExpanded(true); } + d->setExpanded(expandedDirs.contains(d->fullName())); + if (m_recurse && it->childCount()) { expandItems(it, expandedDirs); } } + + it->setHidden(false); } } @@ -416,8 +472,6 @@ QList FileBrowserTreeWidget::expandedDirs( QTreeWidgetItem * item ) con } - - void FileBrowserTreeWidget::keyPressEvent(QKeyEvent * ke ) { // Shorter names for some commonly used properties of the event From 296d5736c8371e365a877f14de8bd45f57ff720f Mon Sep 17 00:00:00 2001 From: Babakinha <59146844+Babakinha@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:57:36 -0300 Subject: [PATCH 06/27] Remember to check for Linux VST Effects (#6751) Remember to also check .so files and not only .dll --- plugins/VstEffect/VstSubPluginFeatures.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/VstEffect/VstSubPluginFeatures.cpp b/plugins/VstEffect/VstSubPluginFeatures.cpp index f929b5526..7eab7a9bf 100644 --- a/plugins/VstEffect/VstSubPluginFeatures.cpp +++ b/plugins/VstEffect/VstSubPluginFeatures.cpp @@ -82,7 +82,11 @@ void VstSubPluginFeatures::addPluginsFromDir( QStringList* filenames, QString pa } } QStringList dlls = QDir( ConfigManager::inst()->vstDir() + path ). - entryList( QStringList() << "*.dll", + entryList( QStringList() << "*.dll" +#ifdef LMMS_BUILD_LINUX + << "*.so" +#endif + , QDir::Files, QDir::Name ); for( int i = 0; i < dlls.size(); i++ ) { From b64912cd57db7bfa2692be42bfa904adc1e72b65 Mon Sep 17 00:00:00 2001 From: consolegrl <5942029+consolegrl@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:35:54 -0400 Subject: [PATCH 07/27] fixes #6354: Sample and Hold for LFO Controller (#6850) * fixes #6354: Sample and Hold for LFO Controller LFO controller's "white noise" wave shape didn't respect the frequency knob at all, so Sample-and-Hold was added to extend the functionality of the LFO Controller with this random waveshape. The original functionallity can still be accessed by setting the FREQ knob to minimum (0.01) --------- Co-authored-by: Kevin Zander Co-authored-by: saker --- include/DataFile.h | 1 + include/LfoController.h | 1 + src/core/DataFile.cpp | 18 ++++++++++++++++++ src/core/LfoController.cpp | 34 ++++++++++++++++++++++++++++++---- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/include/DataFile.h b/include/DataFile.h index 137f0156f..c19a00f7f 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -126,6 +126,7 @@ private: void upgrade_defaultTripleOscillatorHQ(); void upgrade_mixerRename(); void upgrade_bbTcoRename(); + void upgrade_sampleAndHold(); // List of all upgrade methods static const std::vector UPGRADE_METHODS; diff --git a/include/LfoController.h b/include/LfoController.h index 1c63ba698..109edbd3f 100644 --- a/include/LfoController.h +++ b/include/LfoController.h @@ -86,6 +86,7 @@ protected: sample_t (*m_sampleFunction)( const float ); private: + float m_heldSample; SampleBuffer * m_userDefSampleBuffer; protected slots: diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 5c98ec81c..d237d13ae 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -79,6 +79,7 @@ const std::vector DataFile::UPGRADE_METHODS = { &DataFile::upgrade_automationNodes , &DataFile::upgrade_extendedNoteRange, &DataFile::upgrade_defaultTripleOscillatorHQ, &DataFile::upgrade_mixerRename , &DataFile::upgrade_bbTcoRename, + &DataFile::upgrade_sampleAndHold , }; // Vector of all versions that have upgrade routines. @@ -1762,6 +1763,23 @@ void DataFile::upgrade_bbTcoRename() } +// Set LFO speed to 0.01 on projects made before sample-and-hold PR +void DataFile::upgrade_sampleAndHold() +{ + QDomNodeList elements = elementsByTagName("lfocontroller"); + for (int i = 0; i < elements.length(); ++i) + { + if (elements.item(i).isNull()) { continue; } + auto e = elements.item(i).toElement(); + // Correct old random wave LFO speeds + if (e.attribute("wave").toInt() == 6) + { + e.setAttribute("speed",0.01f); + } + } +} + + void DataFile::upgrade() { // Runs all necessary upgrade methods diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index 23621b847..88f64803c 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -88,6 +88,7 @@ void LfoController::updateValueBuffer() { m_phaseOffset = m_phaseModel.value() / 360.0; float phase = m_currentPhase + m_phaseOffset; + float phasePrev = 0.0f; // roll phase up until we're in sync with period counter m_bufferLastUpdated++; @@ -102,20 +103,45 @@ void LfoController::updateValueBuffer() ValueBuffer *amountBuffer = m_amountModel.valueBuffer(); int amountInc = amountBuffer ? 1 : 0; float *amountPtr = amountBuffer ? &(amountBuffer->values()[ 0 ] ) : &amount; + Oscillator::WaveShape waveshape = static_cast(m_waveModel.value()); for( float& f : m_valueBuffer ) { - const float currentSample = m_sampleFunction != nullptr - ? m_sampleFunction( phase ) - : m_userDefSampleBuffer->userWaveSample( phase ); + float currentSample = 0; + switch (waveshape) + { + case Oscillator::WaveShape::WhiteNoise: + { + if (absFraction(phase) < absFraction(phasePrev)) + { + // Resample when phase period has completed + m_heldSample = m_sampleFunction(phase); + } + currentSample = m_heldSample; + break; + } + case Oscillator::WaveShape::UserDefined: + { + currentSample = m_userDefSampleBuffer->userWaveSample(phase); + break; + } + default: + { + if (m_sampleFunction != nullptr) + { + currentSample = m_sampleFunction(phase); + } + } + } f = std::clamp(m_baseModel.value() + (*amountPtr * currentSample / 2.0f), 0.0f, 1.0f); + phasePrev = phase; phase += 1.0 / m_duration; amountPtr += amountInc; } - m_currentPhase = absFraction( phase - m_phaseOffset ); + m_currentPhase = absFraction(phase - m_phaseOffset); m_bufferLastUpdated = s_periods; } From 89baab6b87df8401cea43118a067573c1e99d303 Mon Sep 17 00:00:00 2001 From: MrTopom Date: Tue, 12 Sep 2023 23:30:31 +0200 Subject: [PATCH 08/27] FileDialog : Adding mounted volumes on Linux (#6834) * FileDialog : Adding mounted volumes on Linux * Adding some file systems types and collapsing 2 'if' statements in one * Removing the foreach * Correcting PREPROCESSOR directive --- src/gui/modals/FileDialog.cpp | 58 ++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/gui/modals/FileDialog.cpp b/src/gui/modals/FileDialog.cpp index 512d7179f..a6cf4827a 100644 --- a/src/gui/modals/FileDialog.cpp +++ b/src/gui/modals/FileDialog.cpp @@ -26,11 +26,12 @@ #include #include #include +#include +#include #include "ConfigManager.h" #include "FileDialog.h" - namespace lmms::gui { @@ -45,19 +46,38 @@ FileDialog::FileDialog( QWidget *parent, const QString &caption, setOption( QFileDialog::DontUseNativeDialog ); - // Add additional locations to the sidebar +#ifdef LMMS_BUILD_LINUX + QList urls; +#else QList urls = sidebarUrls(); - urls << QUrl::fromLocalFile( QStandardPaths::writableLocation( QStandardPaths::DesktopLocation ) ); - // Find downloads directory - QDir downloadDir( QDir::homePath() + "/Downloads" ); - if ( ! downloadDir.exists() ) - downloadDir.setPath(QStandardPaths::writableLocation( QStandardPaths::DownloadLocation )); - if ( downloadDir.exists() ) - urls << QUrl::fromLocalFile( downloadDir.absolutePath() ); +#endif - urls << QUrl::fromLocalFile( QStandardPaths::writableLocation( QStandardPaths::MusicLocation ) ); - urls << QUrl::fromLocalFile( ConfigManager::inst()->workingDir() ); + QDir desktopDir; + desktopDir.setPath(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); + if (desktopDir.exists()) + { + urls << QUrl::fromLocalFile(desktopDir.absolutePath()); + } + + QDir downloadDir(QDir::homePath() + "/Downloads"); + if (!downloadDir.exists()) + { + downloadDir.setPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)); + } + if (downloadDir.exists()) + { + urls << QUrl::fromLocalFile(downloadDir.absolutePath()); + } + QDir musicDir; + musicDir.setPath(QStandardPaths::writableLocation(QStandardPaths::MusicLocation)); + if (musicDir.exists()) + { + urls << QUrl::fromLocalFile(musicDir.absolutePath()); + } + + urls << QUrl::fromLocalFile(ConfigManager::inst()->workingDir()); + // Add `/Volumes` directory on OS X systems, this allows the user to browse // external disk drives. #ifdef LMMS_BUILD_APPLE @@ -66,6 +86,22 @@ FileDialog::FileDialog( QWidget *parent, const QString &caption, urls << QUrl::fromLocalFile( volumesDir.absolutePath() ); #endif +#ifdef LMMS_BUILD_LINUX + + // FileSystem types : https://www.javatpoint.com/linux-file-system + QStringList usableFileSystems = {"ext", "ext2", "ext3", "ext4", "jfs", "reiserfs", "ntfs3", "fuse.sshfs", "fuseblk"}; + + for(QStorageInfo storage : QStorageInfo::mountedVolumes()) + { + storage.refresh(); + + if (usableFileSystems.contains(QString(storage.fileSystemType()), Qt::CaseInsensitive) && storage.isValid() && storage.isReady()) + { + urls << QUrl::fromLocalFile(storage.rootPath()); + } + } +#endif + setSidebarUrls(urls); } From 3a0e68c0ac93a743cedca379c66de00d13647d69 Mon Sep 17 00:00:00 2001 From: consolegrl <5942029+consolegrl@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:08:06 -0400 Subject: [PATCH 09/27] fixes #6736: Sample tracks lose FX Channel (#6851) * fixes #6736: Sample tracks lose FX Channel * Styling fixes * Restyled remaining blocks of upgrade routine * Fixed hang due to sleepy typo * Update src/core/DataFile.cpp Co-authored-by: saker --------- Co-authored-by: saker --- src/core/DataFile.cpp | 46 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index d237d13ae..5915b25ef 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -1704,26 +1704,56 @@ void DataFile::upgrade_mixerRename() { // Change nodename to QDomNodeList fxmixer = elementsByTagName("fxmixer"); - for (int i = 0; !fxmixer.item(i).isNull(); ++i) + for (int i = 0; i < fxmixer.length(); ++i) { - fxmixer.item(i).toElement().setTagName("mixer"); + auto item = fxmixer.item(i).toElement(); + if (item.isNull()) + { + continue; + } + item.setTagName("mixer"); } // Change nodename to QDomNodeList fxchannel = elementsByTagName("fxchannel"); - for (int i = 0; !fxchannel.item(i).isNull(); ++i) + for (int i = 0; i < fxchannel.length(); ++i) { - fxchannel.item(i).toElement().setTagName("mixerchannel"); + auto item = fxchannel.item(i).toElement(); + if (item.isNull()) + { + continue; + } + item.setTagName("mixerchannel"); } // Change the attribute fxch of element to mixch QDomNodeList fxch = elementsByTagName("instrumenttrack"); - for(int i = 0; !fxch.item(i).isNull(); ++i) + for (int i = 0; i < fxch.length(); ++i) { - if(fxch.item(i).toElement().hasAttribute("fxch")) + auto item = fxch.item(i).toElement(); + if (item.isNull()) { - fxch.item(i).toElement().setAttribute("mixch", fxch.item(i).toElement().attribute("fxch")); - fxch.item(i).toElement().removeAttribute("fxch"); + continue; + } + if (item.hasAttribute("fxch")) + { + item.setAttribute("mixch", item.attribute("fxch")); + item.removeAttribute("fxch"); + } + } + // Change the attribute fxch of element to mixch + fxch = elementsByTagName("sampletrack"); + for (int i = 0; i < fxch.length(); ++i) + { + auto item = fxch.item(i).toElement(); + if (item.isNull()) + { + continue; + } + if (item.hasAttribute("fxch")) + { + item.setAttribute("mixch", item.attribute("fxch")); + item.removeAttribute("fxch"); } } } From 9b1933e544697bfa67d337ed12e0501d66a66ec0 Mon Sep 17 00:00:00 2001 From: Maxwell Voorhes <100326501+mvoorhes@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:17:36 -0700 Subject: [PATCH 10/27] Added flats to array of keys (#6865) --- src/gui/editors/PianoRoll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index b38335995..751fb9d2a 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -130,7 +130,7 @@ QPixmap* PianoRoll::s_toolKnife = nullptr; SimpleTextFloat * PianoRoll::s_textFloat = nullptr; -static std::array s_noteStrings {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; +static std::array s_noteStrings {"C", "C# / D\u266D", "D", "D# / E\u266D", "E", "F", "F# / G\u266D", "G", "G# / A\u266D", "A", "A# / B\u266D", "B"}; static QString getNoteString(int key) { From d3d710e0adac3798ae65f1e2b34fd582e4c02bc6 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Thu, 14 Sep 2023 23:12:22 +0200 Subject: [PATCH 11/27] Remove identical calls to `InstrumentTrack::processAudioBuffer` Remove identical calls to `InstrumentTrack::processAudioBuffer` which appear in the overridden implementations of `Instrument::play` and `Instrument::playNotes`. Instead the call to `processAudioBuffer` has been moved into `InstrumentPlayHandle::play` and `InstrumentTrack::playNote`. These two methods call the aforementioned methods of `Instrument`. Especially in the case of `InstrumentTrack::playNote` the previous implementation resulted in some unncessary "ping pong" where `InstrumentTrack` called a method on an `Instrument` which then in turn called a method on `InstrumentTrack`. And this was done in almost every instrument. In `InstrumentTrack::playNote` an additional check was added which only calls `processAudioBuffer` if the buffer is not `nullptr`. The reason is that under certain circumstances `PlayHandle::doProcessing` calls the `play` method by explicitly passing a `nullptr` as the buffer. This behavior was added with commit 7bc97f5d5bd. Because it is unknown if this was done for some side effects the code was adjusted so that it behaves identical in this case. Move the complex implementation for `InstrumentPlayHandle::play` and `InstrumentPlayHandle::isFromTrack` into the cpp file and optimize the includes. --- include/InstrumentPlayHandle.h | 38 +++--------------- .../AudioFileProcessor/AudioFileProcessor.cpp | 3 -- plugins/BitInvader/BitInvader.cpp | 2 - plugins/CarlaBase/Carla.cpp | 3 -- plugins/FreeBoy/FreeBoy.cpp | 1 - plugins/GigPlayer/GigPlayer.cpp | 2 - plugins/Kicker/Kicker.cpp | 2 - plugins/Lb302/Lb302.cpp | 1 - plugins/Lv2Instrument/Lv2Instrument.cpp | 2 - plugins/Monstro/Monstro.cpp | 2 - plugins/Nes/Nes.cpp | 2 - plugins/OpulenZ/OpulenZ.cpp | 4 -- plugins/Organic/Organic.cpp | 2 - plugins/Patman/Patman.cpp | 2 - plugins/Sf2Player/Sf2Player.cpp | 2 - plugins/Sfxr/Sfxr.cpp | 3 -- plugins/Sid/SidInstrument.cpp | 2 - plugins/Stk/Mallets/Mallets.cpp | 2 - plugins/TripleOscillator/TripleOscillator.cpp | 2 - plugins/Vestige/Vestige.cpp | 2 - plugins/Vibed/Vibed.cpp | 2 - plugins/Watsyn/Watsyn.cpp | 2 - plugins/Xpressive/Xpressive.cpp | 2 - plugins/ZynAddSubFx/ZynAddSubFx.cpp | 1 - src/core/InstrumentPlayHandle.cpp | 39 +++++++++++++++++++ src/tracks/InstrumentTrack.cpp | 7 ++++ 26 files changed, 51 insertions(+), 81 deletions(-) diff --git a/include/InstrumentPlayHandle.h b/include/InstrumentPlayHandle.h index bbf53d16c..1455134e6 100644 --- a/include/InstrumentPlayHandle.h +++ b/include/InstrumentPlayHandle.h @@ -26,13 +26,14 @@ #define LMMS_INSTRUMENT_PLAY_HANDLE_H #include "PlayHandle.h" -#include "Instrument.h" -#include "NotePlayHandle.h" #include "lmms_export.h" namespace lmms { +class Instrument; +class InstrumentTrack; + class LMMS_EXPORT InstrumentPlayHandle : public PlayHandle { public: @@ -40,46 +41,17 @@ public: ~InstrumentPlayHandle() override = default; - - void play( sampleFrame * _working_buffer ) override - { - // ensure that all our nph's have been processed first - ConstNotePlayHandleList nphv = NotePlayHandle::nphsOfInstrumentTrack( m_instrument->instrumentTrack(), true ); - - bool nphsLeft; - do - { - nphsLeft = false; - for( const NotePlayHandle * constNotePlayHandle : nphv ) - { - NotePlayHandle * notePlayHandle = const_cast( constNotePlayHandle ); - if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done && - !notePlayHandle->isFinished()) - { - nphsLeft = true; - notePlayHandle->process(); - } - } - } - while( nphsLeft ); - - m_instrument->play( _working_buffer ); - } + void play( sampleFrame * _working_buffer ) override; bool isFinished() const override { return false; } - bool isFromTrack( const Track* _track ) const override - { - return m_instrument->isFromTrack( _track ); - } - + bool isFromTrack( const Track* _track ) const override; private: Instrument* m_instrument; - } ; diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.cpp b/plugins/AudioFileProcessor/AudioFileProcessor.cpp index a941e773f..667102207 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.cpp +++ b/plugins/AudioFileProcessor/AudioFileProcessor.cpp @@ -171,9 +171,6 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n, static_cast( m_loopModel.value() ) ) ) { applyRelease( _working_buffer, _n ); - instrumentTrack()->processAudioBuffer( _working_buffer, - frames + offset, _n ); - emit isPlaying( ((handleState *)_n->m_pluginData)->frameIndex() ); } else diff --git a/plugins/BitInvader/BitInvader.cpp b/plugins/BitInvader/BitInvader.cpp index 98ef1e97c..4ea73dc71 100644 --- a/plugins/BitInvader/BitInvader.cpp +++ b/plugins/BitInvader/BitInvader.cpp @@ -307,8 +307,6 @@ void BitInvader::playNote( NotePlayHandle * _n, } applyRelease( _working_buffer, _n ); - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/CarlaBase/Carla.cpp b/plugins/CarlaBase/Carla.cpp index faff94b57..819736e92 100644 --- a/plugins/CarlaBase/Carla.cpp +++ b/plugins/CarlaBase/Carla.cpp @@ -508,7 +508,6 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) if (fHandle == nullptr) { - instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, nullptr); return; } @@ -556,8 +555,6 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) workingBuffer[i][0] = buf1[i]; workingBuffer[i][1] = buf2[i]; } - - instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, nullptr); } bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const TimePos&, f_cnt_t offset) diff --git a/plugins/FreeBoy/FreeBoy.cpp b/plugins/FreeBoy/FreeBoy.cpp index 6450253ee..f2dc95699 100644 --- a/plugins/FreeBoy/FreeBoy.cpp +++ b/plugins/FreeBoy/FreeBoy.cpp @@ -419,7 +419,6 @@ void FreeBoyInstrument::playNote(NotePlayHandle* nph, sampleFrame* workingBuffer } framesLeft -= count; } - instrumentTrack()->processAudioBuffer(workingBuffer, frames + offset, nph); } diff --git a/plugins/GigPlayer/GigPlayer.cpp b/plugins/GigPlayer/GigPlayer.cpp index c2e155a20..0713d3100 100644 --- a/plugins/GigPlayer/GigPlayer.cpp +++ b/plugins/GigPlayer/GigPlayer.cpp @@ -494,8 +494,6 @@ void GigInstrument::play( sampleFrame * _working_buffer ) _working_buffer[i][0] *= m_gain.value(); _working_buffer[i][1] *= m_gain.value(); } - - instrumentTrack()->processAudioBuffer( _working_buffer, frames, nullptr ); } diff --git a/plugins/Kicker/Kicker.cpp b/plugins/Kicker/Kicker.cpp index ef1d623c1..e6418e2da 100644 --- a/plugins/Kicker/Kicker.cpp +++ b/plugins/Kicker/Kicker.cpp @@ -197,8 +197,6 @@ void KickerInstrument::playNote( NotePlayHandle * _n, _working_buffer[f+offset][1] *= fac; } } - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/Lb302/Lb302.cpp b/plugins/Lb302/Lb302.cpp index b8fff2c0b..ee49442d5 100644 --- a/plugins/Lb302/Lb302.cpp +++ b/plugins/Lb302/Lb302.cpp @@ -790,7 +790,6 @@ void Lb302Synth::play( sampleFrame * _working_buffer ) const fpp_t frames = Engine::audioEngine()->framesPerPeriod(); process( _working_buffer, frames ); - instrumentTrack()->processAudioBuffer( _working_buffer, frames, nullptr ); // release_frame = 0; //removed for issue # 1432 } diff --git a/plugins/Lv2Instrument/Lv2Instrument.cpp b/plugins/Lv2Instrument/Lv2Instrument.cpp index 1e45f4e91..32f81d23c 100644 --- a/plugins/Lv2Instrument/Lv2Instrument.cpp +++ b/plugins/Lv2Instrument/Lv2Instrument.cpp @@ -197,8 +197,6 @@ void Lv2Instrument::play(sampleFrame *buf) copyModelsToLmms(); copyBuffersToLmms(buf, fpp); - - instrumentTrack()->processAudioBuffer(buf, fpp, nullptr); } diff --git a/plugins/Monstro/Monstro.cpp b/plugins/Monstro/Monstro.cpp index f588d6b78..2201e4ed9 100644 --- a/plugins/Monstro/Monstro.cpp +++ b/plugins/Monstro/Monstro.cpp @@ -1040,8 +1040,6 @@ void MonstroInstrument::playNote( NotePlayHandle * _n, ms->renderOutput( frames, _working_buffer + offset ); //applyRelease( _working_buffer, _n ); // we have our own release - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } void MonstroInstrument::deleteNotePluginData( NotePlayHandle * _n ) diff --git a/plugins/Nes/Nes.cpp b/plugins/Nes/Nes.cpp index a530ac19b..47122a0c6 100644 --- a/plugins/Nes/Nes.cpp +++ b/plugins/Nes/Nes.cpp @@ -561,8 +561,6 @@ void NesInstrument::playNote( NotePlayHandle * n, sampleFrame * workingBuffer ) nes->renderOutput( workingBuffer + offset, frames ); applyRelease( workingBuffer, n ); - - instrumentTrack()->processAudioBuffer( workingBuffer, frames + offset, n ); } diff --git a/plugins/OpulenZ/OpulenZ.cpp b/plugins/OpulenZ/OpulenZ.cpp index 64f609995..d90d5f343 100644 --- a/plugins/OpulenZ/OpulenZ.cpp +++ b/plugins/OpulenZ/OpulenZ.cpp @@ -412,10 +412,6 @@ void OpulenzInstrument::play( sampleFrame * _working_buffer ) } } emulatorMutex.unlock(); - - // Throw the data to the track... - instrumentTrack()->processAudioBuffer( _working_buffer, frameCount, nullptr ); - } diff --git a/plugins/Organic/Organic.cpp b/plugins/Organic/Organic.cpp index f8a2b0d13..a70da6421 100644 --- a/plugins/Organic/Organic.cpp +++ b/plugins/Organic/Organic.cpp @@ -312,8 +312,6 @@ void OrganicInstrument::playNote( NotePlayHandle * _n, } // -- -- - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/Patman/Patman.cpp b/plugins/Patman/Patman.cpp index a2b829940..668c7f461 100644 --- a/plugins/Patman/Patman.cpp +++ b/plugins/Patman/Patman.cpp @@ -157,8 +157,6 @@ void PatmanInstrument::playNote( NotePlayHandle * _n, play_freq, m_loopedModel.value() ? SampleBuffer::LoopMode::On : SampleBuffer::LoopMode::Off ) ) { applyRelease( _working_buffer, _n ); - instrumentTrack()->processAudioBuffer( _working_buffer, - frames + offset, _n ); } else { diff --git a/plugins/Sf2Player/Sf2Player.cpp b/plugins/Sf2Player/Sf2Player.cpp index d46af5e4f..79bd4b976 100644 --- a/plugins/Sf2Player/Sf2Player.cpp +++ b/plugins/Sf2Player/Sf2Player.cpp @@ -848,7 +848,6 @@ void Sf2Instrument::play( sampleFrame * _working_buffer ) if( m_playingNotes.isEmpty() ) { renderFrames( frames, _working_buffer ); - instrumentTrack()->processAudioBuffer( _working_buffer, frames, nullptr ); return; } @@ -906,7 +905,6 @@ void Sf2Instrument::play( sampleFrame * _working_buffer ) { renderFrames( frames - currentFrame, _working_buffer + currentFrame ); } - instrumentTrack()->processAudioBuffer( _working_buffer, frames, nullptr ); } diff --git a/plugins/Sfxr/Sfxr.cpp b/plugins/Sfxr/Sfxr.cpp index fc39ea0fa..e79b8e2ad 100644 --- a/plugins/Sfxr/Sfxr.cpp +++ b/plugins/Sfxr/Sfxr.cpp @@ -480,9 +480,6 @@ void SfxrInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffe delete[] pitchedBuffer; applyRelease( _working_buffer, _n ); - - instrumentTrack()->processAudioBuffer( _working_buffer, frameNum + offset, _n ); - } diff --git a/plugins/Sid/SidInstrument.cpp b/plugins/Sid/SidInstrument.cpp index f663c3b69..143003f98 100644 --- a/plugins/Sid/SidInstrument.cpp +++ b/plugins/Sid/SidInstrument.cpp @@ -429,8 +429,6 @@ void SidInstrument::playNote( NotePlayHandle * _n, _working_buffer[frame+offset][ch] = s; } } - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/Stk/Mallets/Mallets.cpp b/plugins/Stk/Mallets/Mallets.cpp index 4fb077de5..b746e9491 100644 --- a/plugins/Stk/Mallets/Mallets.cpp +++ b/plugins/Stk/Mallets/Mallets.cpp @@ -359,8 +359,6 @@ void MalletsInstrument::playNote( NotePlayHandle * _n, _working_buffer[frame][1] = ps->nextSampleRight() * ( m_scalers[p] + add_scale ); } - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/TripleOscillator/TripleOscillator.cpp b/plugins/TripleOscillator/TripleOscillator.cpp index f2340d3d6..5b8f6e8ad 100644 --- a/plugins/TripleOscillator/TripleOscillator.cpp +++ b/plugins/TripleOscillator/TripleOscillator.cpp @@ -380,8 +380,6 @@ void TripleOscillator::playNote( NotePlayHandle * _n, applyFadeIn(_working_buffer, _n); applyRelease( _working_buffer, _n ); - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/Vestige/Vestige.cpp b/plugins/Vestige/Vestige.cpp index dd8e9cbef..aff5b7fdc 100644 --- a/plugins/Vestige/Vestige.cpp +++ b/plugins/Vestige/Vestige.cpp @@ -409,8 +409,6 @@ void VestigeInstrument::play( sampleFrame * _buf ) m_plugin->process( nullptr, _buf ); - instrumentTrack()->processAudioBuffer( _buf, frames, nullptr ); - m_pluginMutex.unlock(); } diff --git a/plugins/Vibed/Vibed.cpp b/plugins/Vibed/Vibed.cpp index 3ed51fe79..ad6a3942a 100644 --- a/plugins/Vibed/Vibed.cpp +++ b/plugins/Vibed/Vibed.cpp @@ -251,8 +251,6 @@ void Vibed::playNote(NotePlayHandle* n, sampleFrame* workingBuffer) } } } - - instrumentTrack()->processAudioBuffer(workingBuffer, frames + offset, n); } void Vibed::deleteNotePluginData(NotePlayHandle* n) diff --git a/plugins/Watsyn/Watsyn.cpp b/plugins/Watsyn/Watsyn.cpp index 7603a9c1b..8e49942e1 100644 --- a/plugins/Watsyn/Watsyn.cpp +++ b/plugins/Watsyn/Watsyn.cpp @@ -445,8 +445,6 @@ void WatsynInstrument::playNote( NotePlayHandle * _n, } applyRelease( _working_buffer, _n ); - - instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); } diff --git a/plugins/Xpressive/Xpressive.cpp b/plugins/Xpressive/Xpressive.cpp index b1a17a1ce..babc37231 100644 --- a/plugins/Xpressive/Xpressive.cpp +++ b/plugins/Xpressive/Xpressive.cpp @@ -233,8 +233,6 @@ void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) { const f_cnt_t offset = nph->noteOffset(); ps->renderOutput(frames, working_buffer + offset); - - instrumentTrack()->processAudioBuffer(working_buffer, frames + offset, nph); } void Xpressive::deleteNotePluginData(NotePlayHandle* nph) { diff --git a/plugins/ZynAddSubFx/ZynAddSubFx.cpp b/plugins/ZynAddSubFx/ZynAddSubFx.cpp index 2ec864592..be38bcb79 100644 --- a/plugins/ZynAddSubFx/ZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/ZynAddSubFx.cpp @@ -341,7 +341,6 @@ void ZynAddSubFxInstrument::play( sampleFrame * _buf ) m_plugin->processAudio( _buf ); } m_pluginMutex.unlock(); - instrumentTrack()->processAudioBuffer( _buf, Engine::audioEngine()->framesPerPeriod(), nullptr ); } diff --git a/src/core/InstrumentPlayHandle.cpp b/src/core/InstrumentPlayHandle.cpp index e1a9d9d65..30f5fde38 100644 --- a/src/core/InstrumentPlayHandle.cpp +++ b/src/core/InstrumentPlayHandle.cpp @@ -24,7 +24,10 @@ #include "InstrumentPlayHandle.h" +#include "Instrument.h" #include "InstrumentTrack.h" +#include "Engine.h" +#include "AudioEngine.h" namespace lmms { @@ -37,5 +40,41 @@ InstrumentPlayHandle::InstrumentPlayHandle( Instrument * instrument, InstrumentT setAudioPort( instrumentTrack->audioPort() ); } +void InstrumentPlayHandle::play( sampleFrame * _working_buffer ) +{ + InstrumentTrack * instrumentTrack = m_instrument->instrumentTrack(); + + // ensure that all our nph's have been processed first + ConstNotePlayHandleList nphv = NotePlayHandle::nphsOfInstrumentTrack(instrumentTrack, true ); + + bool nphsLeft; + do + { + nphsLeft = false; + for( const NotePlayHandle * constNotePlayHandle : nphv ) + { + NotePlayHandle * notePlayHandle = const_cast( constNotePlayHandle ); + if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done && + !notePlayHandle->isFinished()) + { + nphsLeft = true; + notePlayHandle->process(); + } + } + } + while( nphsLeft ); + + m_instrument->play( _working_buffer ); + + // Process the audio buffer that the instrument has just worked on... + const fpp_t frames = Engine::audioEngine()->framesPerPeriod(); + instrumentTrack->processAudioBuffer(_working_buffer, frames, nullptr); +} + +bool InstrumentPlayHandle::isFromTrack( const Track* _track ) const +{ + return m_instrument->isFromTrack( _track ); +} + } // namespace lmms \ No newline at end of file diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index a4de188a5..c9b87a4f2 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -579,6 +579,13 @@ void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) { // all is done, so now lets play the note! m_instrument->playNote( n, workingBuffer ); + + if (workingBuffer != nullptr) + { + const fpp_t frames = n->framesLeftForCurrentPeriod(); + const f_cnt_t offset = n->noteOffset(); + this->processAudioBuffer(workingBuffer, frames + offset, n); + } } } From a6b6565687d658350fe84b448676ace5a1c466c7 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Thu, 14 Sep 2023 23:35:16 +0200 Subject: [PATCH 12/27] Remove unused variable Remove the unused variable `frames` in `VestigeInstrument::play` to fix the stricter GitHub build. --- plugins/Vestige/Vestige.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/Vestige/Vestige.cpp b/plugins/Vestige/Vestige.cpp index aff5b7fdc..a696a4b2d 100644 --- a/plugins/Vestige/Vestige.cpp +++ b/plugins/Vestige/Vestige.cpp @@ -399,8 +399,6 @@ void VestigeInstrument::play( sampleFrame * _buf ) { if (!m_pluginMutex.tryLock(Engine::getSong()->isExporting() ? -1 : 0)) {return;} - const fpp_t frames = Engine::audioEngine()->framesPerPeriod(); - if( m_plugin == nullptr ) { m_pluginMutex.unlock(); From d25723cead8dbf46e9b4983e90813ab36325f5dc Mon Sep 17 00:00:00 2001 From: saker Date: Fri, 15 Sep 2023 22:25:54 -0400 Subject: [PATCH 13/27] Update display file name when opening ``PatmanView`` (#6870) * Update display file name when loading Patman * Conditionally update file name --- plugins/Patman/Patman.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/Patman/Patman.cpp b/plugins/Patman/Patman.cpp index a2b829940..e96431e3a 100644 --- a/plugins/Patman/Patman.cpp +++ b/plugins/Patman/Patman.cpp @@ -446,7 +446,7 @@ namespace gui PatmanView::PatmanView( Instrument * _instrument, QWidget * _parent ) : InstrumentViewFixedSize( _instrument, _parent ), - m_pi( nullptr ) + m_pi(castModel()) { setAutoFillBackground( true ); QPalette pal; @@ -487,7 +487,15 @@ PatmanView::PatmanView( Instrument * _instrument, QWidget * _parent ) : "tune_off" ) ); m_tuneButton->setToolTip(tr("Tune mode")); - m_displayFilename = tr( "No file selected" ); + + if (m_pi->m_patchFile.isEmpty()) + { + m_displayFilename = tr("No file selected"); + } + else + { + updateFilename(); + } setAcceptDrops( true ); } From 73f9f36c9afcf65150ae8b1f47d359f2472d3eae Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 16 Sep 2023 13:35:15 +0200 Subject: [PATCH 14/27] Code review changes Remove whitespace in methods and add it to the parenthesis of some statements. Remove underscores from parameter names. Remove usage of `this` pointer. Add `auto` keyword to shorten line length in `InstrumentPlayHandle::play`. Move `const_cast` of `NotePlayHandle` closer to the `process` method as this method is the reason that the cast is needed in the first place. One might also add a version of `nphsOfInstrumentTrack` that returns a non-const result but it seems to be a general problem of a missing clear responsibility so I keep it as is. --- include/InstrumentPlayHandle.h | 9 ++++----- src/core/InstrumentPlayHandle.cpp | 32 +++++++++++++++---------------- src/tracks/InstrumentTrack.cpp | 2 +- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/include/InstrumentPlayHandle.h b/include/InstrumentPlayHandle.h index 1455134e6..dc744b4ff 100644 --- a/include/InstrumentPlayHandle.h +++ b/include/InstrumentPlayHandle.h @@ -37,23 +37,22 @@ class InstrumentTrack; class LMMS_EXPORT InstrumentPlayHandle : public PlayHandle { public: - InstrumentPlayHandle( Instrument * instrument, InstrumentTrack* instrumentTrack ); + InstrumentPlayHandle(Instrument * instrument, InstrumentTrack* instrumentTrack); ~InstrumentPlayHandle() override = default; - void play( sampleFrame * _working_buffer ) override; + void play(sampleFrame * working_buffer) override; bool isFinished() const override { return false; } - bool isFromTrack( const Track* _track ) const override; + bool isFromTrack(const Track* track) const override; private: Instrument* m_instrument; -} ; - +}; } // namespace lmms diff --git a/src/core/InstrumentPlayHandle.cpp b/src/core/InstrumentPlayHandle.cpp index 30f5fde38..097719ad8 100644 --- a/src/core/InstrumentPlayHandle.cpp +++ b/src/core/InstrumentPlayHandle.cpp @@ -33,48 +33,48 @@ namespace lmms { -InstrumentPlayHandle::InstrumentPlayHandle( Instrument * instrument, InstrumentTrack* instrumentTrack ) : - PlayHandle( Type::InstrumentPlayHandle ), - m_instrument( instrument ) +InstrumentPlayHandle::InstrumentPlayHandle(Instrument * instrument, InstrumentTrack* instrumentTrack) : + PlayHandle(Type::InstrumentPlayHandle), + m_instrument(instrument) { - setAudioPort( instrumentTrack->audioPort() ); + setAudioPort(instrumentTrack->audioPort()); } -void InstrumentPlayHandle::play( sampleFrame * _working_buffer ) +void InstrumentPlayHandle::play(sampleFrame * working_buffer) { InstrumentTrack * instrumentTrack = m_instrument->instrumentTrack(); // ensure that all our nph's have been processed first - ConstNotePlayHandleList nphv = NotePlayHandle::nphsOfInstrumentTrack(instrumentTrack, true ); + auto nphv = NotePlayHandle::nphsOfInstrumentTrack(instrumentTrack, true); bool nphsLeft; do { nphsLeft = false; - for( const NotePlayHandle * constNotePlayHandle : nphv ) + for (const NotePlayHandle * constNotePlayHandle : nphv) { - NotePlayHandle * notePlayHandle = const_cast( constNotePlayHandle ); - if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done && - !notePlayHandle->isFinished()) + if (constNotePlayHandle->state() != ThreadableJob::ProcessingState::Done && + !constNotePlayHandle->isFinished()) { nphsLeft = true; + NotePlayHandle * notePlayHandle = const_cast(constNotePlayHandle); notePlayHandle->process(); } } } - while( nphsLeft ); + while (nphsLeft); - m_instrument->play( _working_buffer ); + m_instrument->play(working_buffer); // Process the audio buffer that the instrument has just worked on... const fpp_t frames = Engine::audioEngine()->framesPerPeriod(); - instrumentTrack->processAudioBuffer(_working_buffer, frames, nullptr); + instrumentTrack->processAudioBuffer(working_buffer, frames, nullptr); } -bool InstrumentPlayHandle::isFromTrack( const Track* _track ) const +bool InstrumentPlayHandle::isFromTrack(const Track* track) const { - return m_instrument->isFromTrack( _track ); + return m_instrument->isFromTrack(track); } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index c9b87a4f2..0ffde61bc 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -584,7 +584,7 @@ void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) { const fpp_t frames = n->framesLeftForCurrentPeriod(); const f_cnt_t offset = n->noteOffset(); - this->processAudioBuffer(workingBuffer, frames + offset, n); + processAudioBuffer(workingBuffer, frames + offset, n); } } } From 6c3ae30c8937173bd69ec3f12ccd5996189c3342 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 16 Sep 2023 19:19:37 +0200 Subject: [PATCH 15/27] Add comments about nullptr guard Add some comments which describe why we need to guard agains nullptr. --- src/tracks/InstrumentTrack.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 0ffde61bc..5dee1f3a5 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -570,6 +570,10 @@ f_cnt_t InstrumentTrack::beatLen( NotePlayHandle * _n ) const void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) { + // Note: under certain circumstances the working buffer is a nullptr. + // These cases are triggered in PlayHandle::doProcessing when the play method is called with a nullptr. + // TODO: Find out if we can skip processing at a higher level if the buffer is nullptr. + // arpeggio- and chord-widget has to do its work -> adding sub-notes // for chords/arpeggios m_noteStacking.processNote( n ); @@ -580,6 +584,8 @@ void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) // all is done, so now lets play the note! m_instrument->playNote( n, workingBuffer ); + // Calling processAudioBuffer with a nullptr leads to crashes when checking if the buffer represents silence. + // Therefore we must guard against a nullptr here. if (workingBuffer != nullptr) { const fpp_t frames = n->framesLeftForCurrentPeriod(); From 4348038b0ff2f334f85a37a1caf124213f6d3439 Mon Sep 17 00:00:00 2001 From: Austin <61636545+aakers24@users.noreply.github.com> Date: Sun, 17 Sep 2023 08:34:42 -0700 Subject: [PATCH 16/27] Added automatic dark note on light background for midi clips. (#6539) --- src/gui/clips/MidiClipView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/clips/MidiClipView.cpp b/src/gui/clips/MidiClipView.cpp index 79c4cd73d..151df8d3c 100644 --- a/src/gui/clips/MidiClipView.cpp +++ b/src/gui/clips/MidiClipView.cpp @@ -523,7 +523,8 @@ void MidiClipView::paintEvent( QPaintEvent * ) p.scale(width(), height() - distanceToTop - 2 * notesBorder); // set colour based on mute status - QColor noteFillColor = muted ? getMutedNoteFillColor() : getNoteFillColor(); + QColor noteFillColor = muted ? getMutedNoteFillColor().lighter(200) + : (c.lightness() > 175 ? getNoteFillColor().darker(400) : getNoteFillColor()); QColor noteBorderColor = muted ? getMutedNoteBorderColor() : ( m_clip->hasColor() ? c.lighter( 200 ) : getNoteBorderColor() ); From e9125d3ad3c8d6da568ea64641896a0f71671534 Mon Sep 17 00:00:00 2001 From: Martin Pavelek Date: Sun, 17 Sep 2023 17:55:04 +0200 Subject: [PATCH 17/27] Fix LcdFloatSpinBox constructor and label alignment (#6686) --- src/gui/widgets/LcdFloatSpinBox.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/LcdFloatSpinBox.cpp b/src/gui/widgets/LcdFloatSpinBox.cpp index 6391f314a..96f2b27e1 100644 --- a/src/gui/widgets/LcdFloatSpinBox.cpp +++ b/src/gui/widgets/LcdFloatSpinBox.cpp @@ -49,6 +49,7 @@ namespace lmms::gui LcdFloatSpinBox::LcdFloatSpinBox(int numWhole, int numFrac, const QString& name, QWidget* parent) : + QWidget(parent), FloatModelView(new FloatModel(0, 0, 0, 0, nullptr, name, true), this), m_wholeDisplay(numWhole, parent, name, false), m_fractionDisplay(numFrac, parent, name, true), @@ -62,6 +63,7 @@ LcdFloatSpinBox::LcdFloatSpinBox(int numWhole, int numFrac, const QString& name, LcdFloatSpinBox::LcdFloatSpinBox(int numWhole, int numFrac, const QString& style, const QString& name, QWidget* parent) : + QWidget(parent), FloatModelView(new FloatModel(0, 0, 0, 0, nullptr, name, true), this), m_wholeDisplay(numWhole, style, parent, name, false), m_fractionDisplay(numFrac, style, parent, name, true), @@ -101,6 +103,7 @@ void LcdFloatSpinBox::layoutSetup(const QString &style) outerLayout->setContentsMargins(0, 0, 0, 0); outerLayout->setSizeConstraint(QLayout::SetFixedSize); this->setLayout(outerLayout); + this->setFixedHeight(32); } @@ -240,9 +243,9 @@ void LcdFloatSpinBox::paintEvent(QPaintEvent*) { p.setFont(pointSizeF(p.font(), 6.5)); p.setPen(m_wholeDisplay.textShadowColor()); - p.drawText(width() / 2 - horizontalAdvance(p.fontMetrics(), m_label) / 2 + 1, height(), m_label); + p.drawText(width() / 2 - p.fontMetrics().boundingRect(m_label).width() / 2 + 1, height(), m_label); p.setPen(m_wholeDisplay.textColor()); - p.drawText(width() / 2 - horizontalAdvance(p.fontMetrics(), m_label) / 2, height() - 1, m_label); + p.drawText(width() / 2 - p.fontMetrics().boundingRect(m_label).width() / 2, height() - 1, m_label); } } From 733e0a1e542dec42325d1110688848d4fecf4f56 Mon Sep 17 00:00:00 2001 From: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com> Date: Mon, 18 Sep 2023 22:14:08 +0530 Subject: [PATCH 18/27] Fix invalid use of iterators in piano roll (#6869) --- src/gui/editors/PianoRoll.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 751fb9d2a..1da6aa3df 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -1719,10 +1719,10 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) const NoteVector & notes = m_midiClip->notes(); // will be our iterator in the following loop - auto it = notes.begin() + notes.size() - 1; + auto it = notes.rbegin(); // loop through whole note-vector... - for( int i = 0; i < notes.size(); ++i ) + while (it != notes.rend()) { Note *note = *it; TimePos len = note->length(); @@ -1747,7 +1747,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) { break; } - --it; + ++it; } // first check whether the user clicked in note-edit- @@ -1769,7 +1769,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) Note * created_new_note = nullptr; // did it reach end of vector because // there's no note?? - if( it == notes.begin()-1 ) + if (it == notes.rend()) { is_new_note = true; m_midiClip->addJournalCheckPoint(); @@ -1816,8 +1816,8 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // reset it so that it can be used for // ops (move, resize) after this // code-block - it = notes.begin(); - while( it != notes.end() && *it != created_new_note ) + it = notes.rbegin(); + while (it != notes.rend() && *it != created_new_note) { ++it; } @@ -1933,7 +1933,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) { // erase single note m_mouseDownRight = true; - if( it != notes.begin()-1 ) + if (it != notes.rend()) { m_midiClip->addJournalCheckPoint(); m_midiClip->removeNote( *it ); @@ -2513,7 +2513,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) bool altPressed = me->modifiers() & Qt::AltModifier; // We iterate from last note in MIDI clip to the first, // chronologically - auto it = notes.begin() + notes.size() - 1; + auto it = notes.rbegin(); for( int i = 0; i < notes.size(); ++i ) { Note* n = *it; @@ -2556,7 +2556,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) } - --it; + ++it; } // Emit MIDI clip has changed @@ -2575,10 +2575,10 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) const NoteVector & notes = m_midiClip->notes(); // will be our iterator in the following loop - auto it = notes.begin() + notes.size() - 1; + auto it = notes.rbegin(); // loop through whole note-vector... - for( int i = 0; i < notes.size(); ++i ) + while (it != notes.rend()) { Note *note = *it; // and check whether the cursor is over an @@ -2591,12 +2591,12 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) { break; } - --it; + ++it; } // did it reach end of vector because there's // no note?? - if( it != notes.begin()-1 ) + if (it != notes.rend()) { Note *note = *it; // x coordinate of the right edge of the note From dc88040fbe59222620535a347fc209a020133c71 Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Tue, 19 Sep 2023 00:18:28 +0100 Subject: [PATCH 19/27] Add instrument play handles unconditionally (#6875) --- src/core/AudioEngine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp index 2d077babc..29c54647c 100644 --- a/src/core/AudioEngine.cpp +++ b/src/core/AudioEngine.cpp @@ -701,7 +701,10 @@ void AudioEngine::removeAudioPort(AudioPort * port) bool AudioEngine::addPlayHandle( PlayHandle* handle ) { - if( criticalXRuns() == false ) + // Only add play handles if we have the CPU capacity to process them. + // Instrument play handles are not added during playback, but when the + // associated instrument is created, so add those unconditionally. + if (handle->type() == PlayHandle::Type::InstrumentPlayHandle || !criticalXRuns()) { m_newPlayHandles.push( handle ); handle->audioPort()->addPlayHandle( handle ); From 94d0b9111b24687e44f65cdf1e5c691e249ee50d Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Wed, 20 Sep 2023 00:56:55 +0100 Subject: [PATCH 20/27] Use UTF-8 for MSVC source and execution charset (#6876) --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b17d0e7c..c1cf3406b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -651,6 +651,9 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") ELSE(WIN32) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -DPIC") ENDIF(WIN32) +elseif(MSVC) + # Use UTF-8 as the source and execution character set + add_compile_options("/utf-8") ENDIF() # add enabled sanitizers From 7e8c79a191e2dbb8ac5a2a85fd758b0782d37662 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 20 Sep 2023 19:52:59 +0200 Subject: [PATCH 21/27] Enable build under NixOS (#6855) Explicitly call the perl interpreter when building the SWH LADSPA plugins --- CMakeLists.txt | 20 ++++++++++++++++++-- plugins/LadspaEffect/swh/CMakeLists.txt | 3 ++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1cf3406b..7c3770f31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,13 @@ SET(LMMS_BINARY_DIR ${CMAKE_BINARY_DIR}) SET(LMMS_SOURCE_DIR ${CMAKE_SOURCE_DIR}) # CMAKE_POLICY Section +IF(COMMAND CMAKE_POLICY) + # TODO: Keep CMP0074 but remove this condition when cmake 3.12+ is guaranteed + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.12) + # Needed for the SWH Ladspa plugins. See below. + CMAKE_POLICY(SET CMP0074 NEW) # find_package() uses _ROOT variables + ENDIF() +ENDIF(COMMAND CMAKE_POLICY) # Import of windows.h breaks min()/max() ADD_DEFINITIONS(-DNOMINMAX) @@ -266,8 +273,17 @@ ELSE(WANT_CMT) ENDIF(WANT_CMT) IF(WANT_SWH) - SET(LMMS_HAVE_SWH TRUE) - SET(STATUS_SWH "OK") + IF(LMMS_BUILD_APPLE) + # Prefer system perl over Homebrew, MacPorts, etc + SET(Perl_ROOT "/usr/bin") + ENDIF() + FIND_PACKAGE(Perl) + IF(PERL_FOUND) + SET(LMMS_HAVE_SWH TRUE) + SET(STATUS_SWH "OK") + ELSE() + SET(STATUS_SWH "Skipping, perl is missing") + ENDIF() ELSE(WANT_SWH) SET(STATUS_SWH "not built as requested") ENDIF(WANT_SWH) diff --git a/plugins/LadspaEffect/swh/CMakeLists.txt b/plugins/LadspaEffect/swh/CMakeLists.txt index aec01c22f..a83001177 100644 --- a/plugins/LadspaEffect/swh/CMakeLists.txt +++ b/plugins/LadspaEffect/swh/CMakeLists.txt @@ -16,6 +16,7 @@ SET(COMPILE_FLAGS "${COMPILE_FLAGS} ${PIC_FLAGS}") # Loop over every XML file FILE(GLOB XML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/ladspa/*.xml") LIST(SORT XML_SOURCES) + FOREACH(_item ${XML_SOURCES}) # Get library name and (soon to be) C file GET_FILENAME_COMPONENT(_plugin "${_item}" NAME_WE) @@ -24,7 +25,7 @@ FOREACH(_item ${XML_SOURCES}) # Coerce XML source file to C ADD_CUSTOM_COMMAND( OUTPUT "${_out_file}" - COMMAND ./makestub.pl "${_item}" > "${_out_file}" + COMMAND "${PERL_EXECUTABLE}" ./makestub.pl "${_item}" > "${_out_file}" DEPENDS "${_item}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ladspa" VERBATIM From 3df28e30b68db4d696b50315577bf7a04cd391f7 Mon Sep 17 00:00:00 2001 From: Maxwell Voorhes <100326501+mvoorhes@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:32:21 -0700 Subject: [PATCH 22/27] Changed sharps to music sharps unicode (#6873) --- 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 1da6aa3df..cef2205d2 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -130,7 +130,10 @@ QPixmap* PianoRoll::s_toolKnife = nullptr; SimpleTextFloat * PianoRoll::s_textFloat = nullptr; -static std::array s_noteStrings {"C", "C# / D\u266D", "D", "D# / E\u266D", "E", "F", "F# / G\u266D", "G", "G# / A\u266D", "A", "A# / B\u266D", "B"}; +static std::array s_noteStrings { + "C", "C\u266F / D\u266D", "D", "D\u266F / E\u266D", "E", "F", "F\u266F / G\u266D", + "G", "G\u266F / A\u266D", "A", "A\u266F / B\u266D", "B" +}; static QString getNoteString(int key) { From b6c80bd7366a789cab3f5a6a017636faf80a95ee Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Thu, 21 Sep 2023 19:24:06 +0200 Subject: [PATCH 23/27] Replace check for nullptr Replace the check for a `nullptr` buffer with a check that checks if the NotePlayHandle uses a buffer. This is effectively the same condition that's used by `PlayHandle::doProcessing` to decide if it should call play with a `nullptr` in the first place. Hence it should be the most fitting check. --- src/tracks/InstrumentTrack.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 5dee1f3a5..29fda075e 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -584,9 +584,9 @@ void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) // all is done, so now lets play the note! m_instrument->playNote( n, workingBuffer ); - // Calling processAudioBuffer with a nullptr leads to crashes when checking if the buffer represents silence. - // Therefore we must guard against a nullptr here. - if (workingBuffer != nullptr) + // This is effectively the same as checking if workingBuffer is not a nullptr. + // Calling processAudioBuffer with a nullptr leads to crashes. Hence the check. + if (n->usesBuffer()) { const fpp_t frames = n->framesLeftForCurrentPeriod(); const f_cnt_t offset = n->noteOffset(); From 07229b64048c118bd8a25904c2cbc1a603fad838 Mon Sep 17 00:00:00 2001 From: Alexandre Almeida Date: Thu, 21 Sep 2023 20:18:23 -0300 Subject: [PATCH 24/27] Show error message when loading an invalid sample file (#6286) --- include/SampleClip.h | 2 +- src/core/SampleBuffer.cpp | 62 +++++++++++++++++++++++++++++++-------- src/core/SampleClip.cpp | 29 ++++++++++-------- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/include/SampleClip.h b/include/SampleClip.h index c9e247328..5246787bd 100644 --- a/include/SampleClip.h +++ b/include/SampleClip.h @@ -77,7 +77,7 @@ public: public slots: void setSampleBuffer( lmms::SampleBuffer* sb ); - void setSampleFile( const QString & _sf ); + void setSampleFile( const QString & sf ); void updateLength(); void toggleRecord(); void playbackPositionChanged(); diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 775db125b..5e2d09c57 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -247,7 +247,15 @@ void SampleBuffer::update(bool keepSettings) const int fileSizeMax = 300; // MB const int sampleLengthMax = 90; // Minutes - bool fileLoadError = false; + enum class FileLoadError + { + None, + ReadPermissionDenied, + TooLarge, + Invalid + }; + FileLoadError fileLoadError = FileLoadError::None; + if (m_audioFile.isEmpty() && m_origData != nullptr && m_origFrames > 0) { // TODO: reverse- and amplification-property is not covered @@ -271,31 +279,40 @@ void SampleBuffer::update(bool keepSettings) m_frames = 0; const QFileInfo fileInfo(file); - if (fileInfo.size() > fileSizeMax * 1024 * 1024) + if (!fileInfo.isReadable()) { - fileLoadError = true; + fileLoadError = FileLoadError::ReadPermissionDenied; + } + else if (fileInfo.size() > fileSizeMax * 1024 * 1024) + { + fileLoadError = FileLoadError::TooLarge; } else { // Use QFile to handle unicode file names on Windows QFile f(file); - SNDFILE * sndFile; + SNDFILE * sndFile = nullptr; SF_INFO sfInfo; sfInfo.format = 0; + if (f.open(QIODevice::ReadOnly) && (sndFile = sf_open_fd(f.handle(), SFM_READ, &sfInfo, false))) { f_cnt_t frames = sfInfo.frames; int rate = sfInfo.samplerate; if (frames / rate > sampleLengthMax * 60) { - fileLoadError = true; + fileLoadError = FileLoadError::TooLarge; } sf_close(sndFile); } + else + { + fileLoadError = FileLoadError::Invalid; + } f.close(); } - if (!fileLoadError) + if (fileLoadError == FileLoadError::None) { #ifdef LMMS_HAVE_OGGVORBIS // workaround for a bug in libsndfile or our libsndfile decoder @@ -322,7 +339,7 @@ void SampleBuffer::update(bool keepSettings) } } - if (m_frames == 0 || fileLoadError) // if still no frames, bail + if (m_frames == 0 || fileLoadError != FileLoadError::None) // if still no frames, bail { // sample couldn't be decoded, create buffer containing // one sample-frame @@ -363,16 +380,35 @@ void SampleBuffer::update(bool keepSettings) } Oscillator::generateAntiAliasUserWaveTable(this); - if (fileLoadError) + if (fileLoadError != FileLoadError::None) { QString title = tr("Fail to open file"); - QString message = tr("Audio files are limited to %1 MB " - "in size and %2 minutes of playing time" - ).arg(fileSizeMax).arg(sampleLengthMax); + QString message; + + switch (fileLoadError) + { + case FileLoadError::None: + // present just to avoid a compiler warning + break; + + case FileLoadError::ReadPermissionDenied: + message = tr("Read permission denied"); + break; + + case FileLoadError::TooLarge: + message = tr("Audio files are limited to %1 MB " + "in size and %2 minutes of playing time" + ).arg(fileSizeMax).arg(sampleLengthMax); + break; + + case FileLoadError::Invalid: + message = tr("Invalid audio file"); + break; + } + if (gui::getGUI() != nullptr) { - QMessageBox::information(nullptr, - title, message, QMessageBox::Ok); + QMessageBox::information(nullptr, title, message, QMessageBox::Ok); } else { diff --git a/src/core/SampleClip.cpp b/src/core/SampleClip.cpp index 592a63827..b09d7b3bb 100644 --- a/src/core/SampleClip.cpp +++ b/src/core/SampleClip.cpp @@ -143,23 +143,26 @@ void SampleClip::setSampleBuffer( SampleBuffer* sb ) -void SampleClip::setSampleFile( const QString & _sf ) +void SampleClip::setSampleFile(const QString & sf) { - int length; - if ( _sf.isEmpty() ) - { //When creating an empty sample clip make it a bar long - float nom = Engine::getSong()->getTimeSigModel().getNumerator(); - float den = Engine::getSong()->getTimeSigModel().getDenominator(); - length = DefaultTicksPerBar * ( nom / den ); - } - else - { //Otherwise set it to the sample's length - m_sampleBuffer->setAudioFile( _sf ); + int length = 0; + + if (!sf.isEmpty()) + { + m_sampleBuffer->setAudioFile(sf); length = sampleLength(); } - changeLength(length); - setStartTimeOffset( 0 ); + if (length == 0) + { + //If there is no sample, make the clip a bar long + float nom = Engine::getSong()->getTimeSigModel().getNumerator(); + float den = Engine::getSong()->getTimeSigModel().getDenominator(); + length = DefaultTicksPerBar * (nom / den); + } + + changeLength(length); + setStartTimeOffset(0); emit sampleChanged(); emit playbackPositionChanged(); From 93d3e8c82c4b2968c5949dde0fb8bb4a952bb54f Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Fri, 22 Sep 2023 18:16:45 +0200 Subject: [PATCH 25/27] Adjust the classic theme Adjust the classic theme so that it is consistent with the changes made to the default theme. It was only necessary to change the font-size of the check boxes in the file browser to points because the QTreeView already does not contain any font settings. --- data/themes/classic/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 2880fe661..4c266e064 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -132,7 +132,7 @@ QMenu::indicator:selected { lmms--gui--FileBrowser QCheckBox { - font-size: 10px; + font-size: 8pt; color: white; } From f0aa2862d7efe06a483f6056ba20de315d065597 Mon Sep 17 00:00:00 2001 From: Artur-Twardowski-Mobica <139768112+Artur-Twardowski-Mobica@users.noreply.github.com> Date: Fri, 22 Sep 2023 21:07:25 +0200 Subject: [PATCH 26/27] Updated MIDI CC handling not to count from 1 (#6774) --- include/DataFile.h | 1 + include/MidiController.h | 1 + src/core/DataFile.cpp | 23 ++++++++++++++++++- src/core/midi/MidiController.cpp | 11 ++++----- src/core/midi/MidiPort.cpp | 7 +++--- src/gui/modals/ControllerConnectionDialog.cpp | 6 ++--- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/include/DataFile.h b/include/DataFile.h index c19a00f7f..dc82315ad 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -127,6 +127,7 @@ private: void upgrade_mixerRename(); void upgrade_bbTcoRename(); void upgrade_sampleAndHold(); + void upgrade_midiCCIndexing(); // List of all upgrade methods static const std::vector UPGRADE_METHODS; diff --git a/include/MidiController.h b/include/MidiController.h index c4ef49590..9f49627ac 100644 --- a/include/MidiController.h +++ b/include/MidiController.h @@ -48,6 +48,7 @@ class MidiController : public Controller, public MidiEventProcessor { Q_OBJECT public: + static constexpr int NONE = -1; MidiController( Model * _parent ); ~MidiController() override = default; diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 5915b25ef..8d0a8dca4 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -79,7 +79,7 @@ const std::vector DataFile::UPGRADE_METHODS = { &DataFile::upgrade_automationNodes , &DataFile::upgrade_extendedNoteRange, &DataFile::upgrade_defaultTripleOscillatorHQ, &DataFile::upgrade_mixerRename , &DataFile::upgrade_bbTcoRename, - &DataFile::upgrade_sampleAndHold , + &DataFile::upgrade_sampleAndHold , &DataFile::upgrade_midiCCIndexing }; // Vector of all versions that have upgrade routines. @@ -1809,6 +1809,27 @@ void DataFile::upgrade_sampleAndHold() } } +//! Update MIDI CC indexes, so that they are counted from 0. Older releases of LMMS +//! count the CCs from 1. +void DataFile::upgrade_midiCCIndexing() +{ + static constexpr std::array attributesToUpdate{"inputcontroller", "outputcontroller"}; + + QDomNodeList elements = elementsByTagName("Midicontroller"); + for(int i = 0; i < elements.length(); i++) + { + if (elements.item(i).isNull()) { continue; } + auto element = elements.item(i).toElement(); + for (const char* attrName : attributesToUpdate) + { + if (element.hasAttribute(attrName)) + { + int cc = element.attribute(attrName).toInt(); + element.setAttribute(attrName, cc - 1); + } + } + } +} void DataFile::upgrade() { diff --git a/src/core/midi/MidiController.cpp b/src/core/midi/MidiController.cpp index d7c89e940..0ae76d352 100644 --- a/src/core/midi/MidiController.cpp +++ b/src/core/midi/MidiController.cpp @@ -72,21 +72,20 @@ void MidiController::updateName() -void MidiController::processInEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) +void MidiController::processInEvent(const MidiEvent& event, const TimePos& time, f_cnt_t offset) { unsigned char controllerNum; - switch( event.type() ) + switch(event.type()) { case MidiControlChange: controllerNum = event.controllerNumber(); - if( m_midiPort.inputController() == controllerNum + 1 && - ( m_midiPort.inputChannel() == event.channel() + 1 || - m_midiPort.inputChannel() == 0 ) ) + if (m_midiPort.inputController() == controllerNum && + (m_midiPort.inputChannel() == event.channel() + 1 || m_midiPort.inputChannel() == 0)) { unsigned char val = event.controllerValue(); m_previousValue = m_lastValue; - m_lastValue = (float)( val ) / 127.0f; + m_lastValue = static_cast(val) / 127.0f; emit valueChanged(); } break; diff --git a/src/core/midi/MidiPort.cpp b/src/core/midi/MidiPort.cpp index c7c947e8e..24263f913 100644 --- a/src/core/midi/MidiPort.cpp +++ b/src/core/midi/MidiPort.cpp @@ -31,6 +31,7 @@ #include "MidiEventProcessor.h" #include "Note.h" #include "Song.h" +#include "MidiController.h" namespace lmms @@ -54,8 +55,8 @@ MidiPort::MidiPort( const QString& name, m_mode( mode ), m_inputChannelModel( 0, 0, MidiChannelCount, this, tr( "Input channel" ) ), m_outputChannelModel( 1, 0, MidiChannelCount, this, tr( "Output channel" ) ), - m_inputControllerModel( 0, 0, MidiControllerCount, this, tr( "Input controller" ) ), - m_outputControllerModel( 0, 0, MidiControllerCount, this, tr( "Output controller" ) ), + m_inputControllerModel(MidiController::NONE, MidiController::NONE, MidiControllerCount - 1, this, tr( "Input controller" )), + m_outputControllerModel(MidiController::NONE, MidiController::NONE, MidiControllerCount - 1, this, tr( "Output controller" )), m_fixedInputVelocityModel( -1, -1, MidiMaxVelocity, this, tr( "Fixed input velocity" ) ), m_fixedOutputVelocityModel( -1, -1, MidiMaxVelocity, this, tr( "Fixed output velocity" ) ), m_fixedOutputNoteModel( -1, -1, MidiMaxKey, this, tr( "Fixed output note" ) ), @@ -436,4 +437,4 @@ void MidiPort::invalidateCilent() } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/gui/modals/ControllerConnectionDialog.cpp b/src/gui/modals/ControllerConnectionDialog.cpp index 79daa25b5..4d1090d5c 100644 --- a/src/gui/modals/ControllerConnectionDialog.cpp +++ b/src/gui/modals/ControllerConnectionDialog.cpp @@ -54,7 +54,7 @@ public: AutoDetectMidiController( Model* parent ) : MidiController( parent ), m_detectedMidiChannel( 0 ), - m_detectedMidiController( 0 ) + m_detectedMidiController(NONE) { updateName(); } @@ -69,7 +69,7 @@ public: ( m_midiPort.inputChannel() == 0 || m_midiPort.inputChannel() == event.channel() + 1 ) ) { m_detectedMidiChannel = event.channel() + 1; - m_detectedMidiController = event.controllerNumber() + 1; + m_detectedMidiController = event.controllerNumber(); m_detectedMidiPort = Engine::audioEngine()->midiClient()->sourcePortName( event ); emit valueChanged(); @@ -152,7 +152,7 @@ ControllerConnectionDialog::ControllerConnectionDialog( QWidget * _parent, m_midiControllerSpinBox = new LcdSpinBox( 3, m_midiGroupBox, tr( "Input controller" ) ); - m_midiControllerSpinBox->addTextForValue( 0, "---" ); + m_midiControllerSpinBox->addTextForValue(MidiController::NONE, "---" ); m_midiControllerSpinBox->setLabel( tr( "CONTROLLER" ) ); m_midiControllerSpinBox->move( 68, 24 ); From 49c713df5bad0c7285dd04d236ea3f5e9f3c34ef Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 23 Sep 2023 19:33:20 -0400 Subject: [PATCH 27/27] Use resid submodule from libsidplayfp (#6883) --- .gitmodules | 6 +-- CMakeLists.txt | 24 ++++++++--- plugins/Sid/CMakeLists.txt | 47 +++------------------- plugins/Sid/SidInstrument.cpp | 24 +++++------ plugins/Sid/resid | 1 - plugins/Sid/resid/CMakeLists.txt | 68 ++++++++++++++++++++++++++++++++ plugins/Sid/resid/resid | 1 + 7 files changed, 108 insertions(+), 63 deletions(-) delete mode 160000 plugins/Sid/resid create mode 100644 plugins/Sid/resid/CMakeLists.txt create mode 160000 plugins/Sid/resid/resid diff --git a/.gitmodules b/.gitmodules index ee6e7eac9..fa6980ac5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,9 +40,9 @@ [submodule "plugins/CarlaBase/carla"] path = plugins/CarlaBase/carla url = https://github.com/falktx/carla -[submodule "plugins/Sid/resid"] - path = plugins/Sid/resid - url = https://github.com/simonowen/resid +[submodule "plugins/Sid/resid/resid"] + path = plugins/Sid/resid/resid + url = https://github.com/libsidplayfp/resid [submodule "src/3rdparty/jack2"] path = src/3rdparty/jack2 url = https://github.com/jackaudio/jack2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c3770f31..4163ca5cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ OPTION(WANT_SOUNDIO "Include libsoundio support" ON) OPTION(WANT_SDL "Include SDL (Simple DirectMedia Layer) support" ON) OPTION(WANT_SF2 "Include SoundFont2 player plugin" ON) OPTION(WANT_GIG "Include GIG player plugin" ON) +option(WANT_SID "Include Sid instrument" ON) OPTION(WANT_STK "Include Stk (Synthesis Toolkit) support" ON) OPTION(WANT_SWH "Include Steve Harris's LADSPA plugins" ON) OPTION(WANT_TAP "Include Tom's Audio Processing LADSPA plugins" ON) @@ -211,6 +212,13 @@ CHECK_CXX_SOURCE_COMPILES( LMMS_HAVE_SF_COMPLEVEL ) +# check for perl +if(LMMS_BUILD_APPLE) + # Prefer system perl over Homebrew, MacPorts, etc + set(Perl_ROOT "/usr/bin") +endif() +find_package(Perl) + IF(WANT_LV2) IF(PKG_CONFIG_FOUND) PKG_CHECK_MODULES(LV2 lv2) @@ -273,11 +281,6 @@ ELSE(WANT_CMT) ENDIF(WANT_CMT) IF(WANT_SWH) - IF(LMMS_BUILD_APPLE) - # Prefer system perl over Homebrew, MacPorts, etc - SET(Perl_ROOT "/usr/bin") - ENDIF() - FIND_PACKAGE(Perl) IF(PERL_FOUND) SET(LMMS_HAVE_SWH TRUE) SET(STATUS_SWH "OK") @@ -349,6 +352,16 @@ IF(WANT_SDL AND NOT LMMS_HAVE_SDL2) ENDIF() ENDIF() +# check for Sid +if(WANT_SID) + if(PERL_FOUND) + set(LMMS_HAVE_SID TRUE) + set(STATUS_SID "OK") + else() + set(STATUS_SID "not found, please install perl if you require the Sid instrument") + endif() +endif() + # check for Stk IF(WANT_STK) FIND_PACKAGE(STK) @@ -816,6 +829,7 @@ MESSAGE( "* ZynAddSubFX instrument : ${STATUS_ZYN}\n" "* Carla Patchbay & Rack : ${STATUS_CARLA}\n" "* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n" +"* Sid instrument : ${STATUS_SID}\n" "* Stk Mallets : ${STATUS_STK}\n" "* VST-instrument hoster : ${STATUS_VST}\n" "* VST-effect hoster : ${STATUS_VST}\n" diff --git a/plugins/Sid/CMakeLists.txt b/plugins/Sid/CMakeLists.txt index c9fce7bb7..c771fc66d 100644 --- a/plugins/Sid/CMakeLists.txt +++ b/plugins/Sid/CMakeLists.txt @@ -1,51 +1,14 @@ INCLUDE(BuildPlugin) -INCLUDE_DIRECTORIES(resid) +if(NOT LMMS_HAVE_SID) + return() +endif() BUILD_PLUGIN(sid SidInstrument.cpp SidInstrument.h - resid/envelope.h - resid/extfilt.h - resid/filter.h - resid/pot.h - resid/siddefs.h - resid/sid.h - resid/spline.h - resid/voice.h - resid/wave.h - resid/envelope.cc - resid/extfilt.cc - resid/filter.cc - resid/pot.cc - resid/sid.cc - resid/version.cc - resid/voice.cc - resid/wave6581_PS_.cc - resid/wave6581_PST.cc - resid/wave6581_P_T.cc - resid/wave6581__ST.cc - resid/wave8580_PS_.cc - resid/wave8580_PST.cc - resid/wave8580_P_T.cc - resid/wave8580__ST.cc - resid/wave.cc MOCFILES SidInstrument.h EMBEDDED_RESOURCES *.png) -# Parse VERSION -FILE(READ "resid/CMakeLists.txt" lines) -STRING(REGEX MATCH "set\\(MAJOR_VER [A-Za-z0-9_]*\\)" MAJOR_RAW ${lines}) -STRING(REGEX MATCH "set\\(MINOR_VER [A-Za-z0-9_]*\\)" MINOR_RAW ${lines}) -STRING(REGEX MATCH "set\\(PATCH_VER [A-Za-z0-9_]*\\)" PATCH_RAW ${lines}) -SEPARATE_ARGUMENTS(MAJOR_RAW) -SEPARATE_ARGUMENTS(MINOR_RAW) -SEPARATE_ARGUMENTS(PATCH_RAW) -LIST(GET MAJOR_RAW 1 MAJOR_RAW) -LIST(GET MINOR_RAW 1 MINOR_RAW) -LIST(GET PATCH_RAW 1 PATCH_RAW) -STRING(REPLACE ")" "" MAJOR_VER "${MAJOR_RAW}") -STRING(REPLACE ")" "" MINOR_VER "${MINOR_RAW}") -STRING(REPLACE ")" "" PATCH_VER "${PATCH_RAW}") - -TARGET_COMPILE_DEFINITIONS(sid PRIVATE VERSION="${MAJOR_VER}.${MINOR_VER}.${PATCH_VER}") +add_subdirectory(resid) +target_link_libraries(sid resid) diff --git a/plugins/Sid/SidInstrument.cpp b/plugins/Sid/SidInstrument.cpp index 143003f98..7f9edf13f 100644 --- a/plugins/Sid/SidInstrument.cpp +++ b/plugins/Sid/SidInstrument.cpp @@ -239,7 +239,7 @@ f_cnt_t SidInstrument::desiredReleaseFrames() const -static int sid_fillbuffer(unsigned char* sidreg, SID *sid, int tdelta, short *ptr, int samples) +static int sid_fillbuffer(unsigned char* sidreg, reSID::SID *sid, int tdelta, short *ptr, int samples) { int tdelta2; int result; @@ -302,9 +302,9 @@ void SidInstrument::playNote( NotePlayHandle * _n, if (!_n->m_pluginData) { - SID *sid = new SID(); - sid->set_sampling_parameters( clockrate, SAMPLE_FAST, samplerate ); - sid->set_chip_model( MOS8580 ); + auto sid = new reSID::SID(); + sid->set_sampling_parameters(clockrate, reSID::SAMPLE_FAST, samplerate); + sid->set_chip_model(reSID::MOS8580); sid->enable_filter( true ); sid->reset(); _n->m_pluginData = sid; @@ -312,7 +312,7 @@ void SidInstrument::playNote( NotePlayHandle * _n, const fpp_t frames = _n->framesLeftForCurrentPeriod(); const f_cnt_t offset = _n->noteOffset(); - SID *sid = static_cast( _n->m_pluginData ); + auto sid = static_cast(_n->m_pluginData); int delta_t = clockrate * frames / samplerate + 4; // avoid variable length array for msvc compat auto buf = reinterpret_cast(_working_buffer + offset); @@ -325,20 +325,20 @@ void SidInstrument::playNote( NotePlayHandle * _n, if( (ChipModel)m_chipModel.value() == ChipModel::MOS6581 ) { - sid->set_chip_model( MOS6581 ); + sid->set_chip_model(reSID::MOS6581); } else { - sid->set_chip_model( MOS8580 ); + sid->set_chip_model(reSID::MOS8580); } // voices - reg8 data8 = 0; - reg8 data16 = 0; - reg8 base = 0; + reSID::reg8 data8 = 0; + reSID::reg16 data16 = 0; + size_t base = 0; float freq = 0.0; float note = 0.0; - for( reg8 i = 0 ; i < 3 ; ++i ) + for (size_t i = 0; i < 3; ++i) { base = i*7; // freq ( Fn = Fout / Fclk * 16777216 ) + coarse detuning @@ -436,7 +436,7 @@ void SidInstrument::playNote( NotePlayHandle * _n, void SidInstrument::deleteNotePluginData( NotePlayHandle * _n ) { - delete static_cast( _n->m_pluginData ); + delete static_cast(_n->m_pluginData); } diff --git a/plugins/Sid/resid b/plugins/Sid/resid deleted file mode 160000 index 02afcc5ce..000000000 --- a/plugins/Sid/resid +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 02afcc5cefac34bd0c665dc0fa6b748d238c1831 diff --git a/plugins/Sid/resid/CMakeLists.txt b/plugins/Sid/resid/CMakeLists.txt new file mode 100644 index 000000000..bb39e3d16 --- /dev/null +++ b/plugins/Sid/resid/CMakeLists.txt @@ -0,0 +1,68 @@ +# These are the defaults +set(RESID_INLINING 1) +set(RESID_INLINE inline) +set(RESID_BRANCH_HINTS 1) +set(NEW_8580_FILTER 0) + +set(HAVE_BOOL 1) +set(HAVE_LOG1P 1) + +if(CMAKE_CXX_COMPILER_ID MATCHES "GCC|Clang") + set(HAVE_BUILTIN_EXPECT 1) +else() + set(HAVE_BUILTIN_EXPECT 0) +endif() + +configure_file(resid/siddefs.h.in resid/siddefs.h @ONLY) + +add_library(resid_objects OBJECT + resid/sid.cc + resid/voice.cc + resid/wave.cc + resid/envelope.cc + resid/filter.cc + resid/dac.cc + resid/extfilt.cc + resid/pot.cc + resid/version.cc +) + +target_include_directories(resid_objects PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/resid" + "${CMAKE_CURRENT_BINARY_DIR}/resid" +) +target_compile_definitions(resid_objects PUBLIC VERSION="1.0") + +set(RESID_WAVES + wave6581_PST + wave6581_PS_ + wave6581_P_T + wave6581__ST + wave8580_PST + wave8580_PS_ + wave8580_P_T + wave8580__ST +) + +set(RESID_SAMP2SRC_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/resid/samp2src.pl) +foreach(WAVE_DATA IN LISTS RESID_WAVES) + set(WAVE_DATA_IN ${CMAKE_CURRENT_SOURCE_DIR}/resid/${WAVE_DATA}.dat) + set(WAVE_SRC_OUT ${CMAKE_CURRENT_BINARY_DIR}/resid/${WAVE_DATA}.h) + set(WAVE_COMMAND + "${PERL_EXECUTABLE}" + "${RESID_SAMP2SRC_SCRIPT}" + "${WAVE_DATA}" + "${WAVE_DATA_IN}" + "${WAVE_SRC_OUT}" + ) + add_custom_command(OUTPUT ${WAVE_SRC_OUT} COMMAND ${WAVE_COMMAND} VERBATIM) + target_sources(resid_objects PUBLIC ${WAVE_SRC_OUT}) +endforeach() + +# TODO CMake 3.12: Use target_link_libraries() to propagate usage requirements directly to sid plugin +add_library(resid INTERFACE) + +target_sources(resid INTERFACE $) + +get_target_property(resid_includes resid_objects INCLUDE_DIRECTORIES) +target_include_directories(resid INTERFACE ${resid_includes}) diff --git a/plugins/Sid/resid/resid b/plugins/Sid/resid/resid new file mode 160000 index 000000000..ef72462f5 --- /dev/null +++ b/plugins/Sid/resid/resid @@ -0,0 +1 @@ +Subproject commit ef72462f5fa0682d099413512b764ae479e77f9b