From 70d7c0c62ca8cf9f6c10dad47d771e52e1e51aae Mon Sep 17 00:00:00 2001
From: Greedysky <greedysky@163.com>
Date: Sat, 16 May 2026 19:48:40 +0800
Subject: [PATCH] feat: Add sidplayfp-3.0 support and fix memory leak[245148]

---
 .../plugins/Input/main/sid/decoder_sid.cpp    | 67 +++++++++++++------
 qmmp/src/plugins/Input/main/sid/decoder_sid.h |  5 +-
 .../plugins/Input/main/sid/settingsdialog.cpp | 29 ++++++--
 .../plugins/Input/main/sid/settingsdialog.ui  |  2 +-
 qmmp/src/plugins/Input/main/sid/sid.pro       |  2 +
 .../Input/tracker/openmpt/settingsdialog.cpp  |  6 +-
 6 files changed, 77 insertions(+), 34 deletions(-)

diff --git a/qmmp/src/plugins/Input/main/sid/decoder_sid.cpp b/qmmp/src/plugins/Input/main/sid/decoder_sid.cpp
index a13ef696b..3a8959544 100644
--- qmmp/src/plugins/Input/main/sid/decoder_sid.cpp
+++ qmmp/src/plugins/Input/main/sid/decoder_sid.cpp
@@ -1,8 +1,14 @@
 #include <sidplayfp/sidplayfp.h>
 #include <sidplayfp/SidTune.h>
 #include <sidplayfp/sidbuilder.h>
-#include <sidplayfp/builders/residfp.h>
-#include <sidplayfp/builders/resid.h>
+#if LIBSIDPLAYFP_VERSION_MAJ >= 3
+#  include <sidplayfp/builders/sidlite.h>
+#else
+#  include <sidplayfp/builders/resid.h>
+#endif
+#ifdef HAVE_RESIDFP_HEADER
+#  include <sidplayfp/builders/residfp.h>
+#endif
 #include <sidplayfp/SidInfo.h>
 #include <sidplayfp/SidTuneInfo.h>
 #include <sidplayfp/SidDatabase.h>
@@ -35,14 +41,15 @@
     int track = -1;
     const QString &filePath = TrackInfo::pathFromUrl(m_path, &track);
 
-    m_tune.load(QmmpPrintable(filePath));
-    if(!m_tune.getInfo())
+    m_tune = std::unique_ptr<SidTune>(new SidTune(nullptr));
+    m_tune->load(QmmpPrintable(filePath));
+    if(!m_tune->getInfo())
     {
-        qWarning("DecoderSID: unable to load tune, error: %s", m_tune.statusString());
+        qWarning("DecoderSID: unable to load tune, error: %s, %s", m_tune->statusString(), qPrintable(filePath));
         return false;
     }
 
-    int count = m_tune.getInfo()->songs();
+    int count = m_tune->getInfo()->songs();
     if(track == 0)
         track = count;
 
@@ -52,15 +59,15 @@
         return false;
     }
 
-    m_tune.selectSong(track);
-    if(!m_tune.getStatus())
+    m_tune->selectSong(track);
+    if(!m_tune->getStatus())
     {
-        qWarning("DecoderSID: error: %s", m_tune.statusString());
+        qWarning("DecoderSID: error: %s", m_tune->statusString());
         return false;
     }
 
     //send metadata for pseudo-protocol
-    const SidTuneInfo *tune_info = m_tune.getInfo();
+    const SidTuneInfo *tune_info = m_tune->getInfo();
     QMap<Qmmp::MetaData, QString> metadata;
     metadata.insert(Qmmp::TITLE,  tune_info->infoString(0));
     metadata.insert(Qmmp::ARTIST, tune_info->infoString(1));
@@ -75,7 +82,7 @@
     if(settings.value("use_hvsc", false).toBool())
     {
         char md5[SidTune::MD5_LENGTH + 1];
-        m_tune.createMD5(md5);
+        m_tune->createMD5(md5);
         m_length = m_db->length(md5, track) * 1000;
     }
 
@@ -86,25 +93,41 @@
 
     qDebug("DecoderSID: song length: %ld", m_length);
 
-    sidbuilder *rs = nullptr;
+#if LIBSIDPLAYFP_VERSION_MAJ >= 3
+# ifdef HAVE_RESIDFP_HEADER
+    if(settings.value("engine", "sidlite").toString() == "residfp")
+    {
+        m_builder = std::unique_ptr<ReSIDfpBuilder>(new ReSIDfpBuilder("ReSIDfp"));
+    }
+    else
+# endif
+    {
+        m_builder = std::unique_ptr<SIDLiteBuilder>(new SIDLiteBuilder("SIDLite"));
+    }
+#else
+# ifdef HAVE_RESIDFP_HEADER
     if(settings.value("engine", "residfp").toString() == "residfp")
     {
-        rs = new ReSIDfpBuilder("ReSIDfp builder");
-        qDebug("DecoderSID: using ReSIDfp emulation");
+        m_builder = std::unique_ptr<ReSIDfpBuilder>(new ReSIDfpBuilder("ReSIDfp"));
     }
     else
+# endif
     {
-        rs = new ReSIDBuilder("ReSID builder");
-        qDebug("DecoderSID: using ReSID emulation");
+        m_builder = std::unique_ptr<ReSIDBuilder>(new ReSIDBuilder("ReSID"));
     }
-    rs->create(m_player->info().maxsids());
+    m_builder->create(m_player->info().maxsids());
+#endif
+
+    qDebug("DecoderSID: using %s emulation", m_builder->name());
 
     SidConfig cfg = m_player->config();
-    cfg.frequency    = settings.value("sample_rate", 48000).toInt();
-    cfg.samplingMethod = (SidConfig::sampling_method_t)settings.value("resampling_method", SidConfig::INTERPOLATE).toInt();
-    cfg.playback     = SidConfig::STEREO;
-    cfg.sidEmulation = rs;
+    cfg.frequency = settings.value("sample_rate", 48000).toInt();
+    cfg.samplingMethod = static_cast<SidConfig::sampling_method_t>(settings.value("resampling_method", SidConfig::INTERPOLATE).toInt());
+    cfg.sidEmulation = m_builder.get();
+#if LIBSIDPLAYFP_VERSION_MAJ < 3
+    cfg.playback = SidConfig::STEREO;
     cfg.fastSampling = settings.value("fast_resampling", false).toBool();
+#endif
     settings.endGroup();
 
     if(!m_player->config(cfg))
@@ -113,7 +136,7 @@
         return false;
     }
 
-    if(!m_player->load(&m_tune))
+    if(!m_player->load(m_tune.get()))
     {
         qWarning("DecoderSID: unable to load tune, error: %s", m_player->error());
         return false;
diff --git a/qmmp/src/plugins/Input/main/sid/decoder_sid.h b/qmmp/src/plugins/Input/main/sid/decoder_sid.h
index 691d9a634..b820cc9ae 100644
--- qmmp/src/plugins/Input/main/sid/decoder_sid.h
+++ qmmp/src/plugins/Input/main/sid/decoder_sid.h
@@ -21,11 +21,13 @@
 #ifndef DECODER_SID_H
 #define DECODER_SID_H
 
+#include <memory>
 #include <qmmp/decoder.h>
 
 class sidplayfp;
 class SidDatabase;
 class SidTune;
+class sidbuilder;
 
 /**
    @author Ilya Kotov <forkotov02@ya.ru>
@@ -50,7 +52,8 @@ class DecoderSID : public Decoder
     qint64 m_length = 0;
     qint64 m_length_in_bytes = 0;
     qint64 m_read_bytes = 0;
-    SidTune m_tune;
+    std::unique_ptr<SidTune> m_tune;
+    std::unique_ptr<sidbuilder> m_builder;
 
 };
 
diff --git a/qmmp/src/plugins/Input/main/sid/settingsdialog.cpp b/qmmp/src/plugins/Input/main/sid/settingsdialog.cpp
index e0d422899..2098083c8 100644
--- qmmp/src/plugins/Input/main/sid/settingsdialog.cpp
+++ qmmp/src/plugins/Input/main/sid/settingsdialog.cpp
@@ -3,6 +3,7 @@
 #include <QSettings>
 #include <qmmp/qmmp.h>
 #include <sidplayfp/SidConfig.h>
+#include <sidplayfp/sidplayfp.h>
 
 SettingsDialog::SettingsDialog(SidDatabase *db, QWidget *parent)
     : QDialog(parent)
@@ -25,20 +26,33 @@ SettingsDialog::SettingsDialog(SidDatabase *db, QWidget *parent)
 
     m_ui.sampleRateComboBox->addItem("44100", 44100);
     m_ui.sampleRateComboBox->addItem("48000", 48000);
-    int i = m_ui.sampleRateComboBox->findData(settings.value("sample_rate", 48000).toInt());
-    m_ui.sampleRateComboBox->setCurrentIndex(i);
+    int index = m_ui.sampleRateComboBox->findData(settings.value("sample_rate", 48000).toInt());
+    m_ui.sampleRateComboBox->setCurrentIndex(index);
 
+#if LIBSIDPLAYFP_VERSION_MAJ >= 3
+    m_ui.emuComboBox->addItem("SIDLite", "sidlite");
+    m_ui.emuComboBox->addItem("ReSIDfp", "residfp");
+    index = m_ui.emuComboBox->findData(settings.value("engine", "sidlite").toString());
+    m_ui.emuComboBox->setCurrentIndex(qMax(index, 0));
+    m_ui.fastResampligCheckBox->setVisible(false);
+#else
     m_ui.emuComboBox->addItem("ReSID", "resid");
     m_ui.emuComboBox->addItem("ReSIDfp", "residfp");
-    i = m_ui.emuComboBox->findData(settings.value("engine", "residfp").toString());
-    m_ui.emuComboBox->setCurrentIndex(i);
-
+    index = m_ui.emuComboBox->findData(settings.value("engine", "residfp").toString());
+    m_ui.emuComboBox->setCurrentIndex(qMax(index, 0));
     m_ui.fastResampligCheckBox->setChecked(settings.value("fast_resampling", false).toBool());
+#endif
+
+// TODO use QFormLayout::setRowVisible
+#ifndef HAVE_RESIDFP_HEADER
+    m_ui.emulationLabel->setVisible(false);
+    m_ui.emuComboBox->setVisible(false);
+#endif
 
     m_ui.resamplingComboBox->addItem("Interpolate", SidConfig::INTERPOLATE);
     m_ui.resamplingComboBox->addItem("Resample interpolate", SidConfig::RESAMPLE_INTERPOLATE);
-    i = m_ui.resamplingComboBox->findData(settings.value("resampling_method", SidConfig::INTERPOLATE).toInt());
-    m_ui.resamplingComboBox->setCurrentIndex(i);
+    index = m_ui.resamplingComboBox->findData(settings.value("resampling_method", SidConfig::INTERPOLATE).toInt());
+    m_ui.resamplingComboBox->setCurrentIndex(index);
 
     settings.endGroup();
 }
diff --git a/qmmp/src/plugins/Input/main/sid/settingsdialog.ui b/qmmp/src/plugins/Input/main/sid/settingsdialog.ui
index bca2e2688..43cdcf8a2 100644
--- qmmp/src/plugins/Input/main/sid/settingsdialog.ui
+++ qmmp/src/plugins/Input/main/sid/settingsdialog.ui
@@ -145,7 +145,7 @@
     </widget>
    </item>
    <item row="6" column="0">
-    <widget class="QLabel" name="label_3">
+    <widget class="QLabel" name="emulationLabel">
      <property name="text">
       <string>Emulation:</string>
      </property>
diff --git a/qmmp/src/plugins/Input/main/sid/sid.pro b/qmmp/src/plugins/Input/main/sid/sid.pro
index 32826f68c..5c136f22e 100644
--- qmmp/src/plugins/Input/main/sid/sid.pro
+++ qmmp/src/plugins/Input/main/sid/sid.pro
@@ -14,6 +14,8 @@ SOURCES += decodersidfactory.cpp \
 
 FORMS += settingsdialog.ui
 
+DEFINES += HAVE_RESIDFP_HEADER
+
 INCLUDEPATH += $$EXTRA_LIB_PATH/libsidplayfp/include
 
 win32{
diff --git a/qmmp/src/plugins/Input/tracker/openmpt/settingsdialog.cpp b/qmmp/src/plugins/Input/tracker/openmpt/settingsdialog.cpp
index 0d7a4da0a..d6e053438 100644
--- qmmp/src/plugins/Input/tracker/openmpt/settingsdialog.cpp
+++ qmmp/src/plugins/Input/tracker/openmpt/settingsdialog.cpp
@@ -50,9 +50,9 @@ void SettingsDialog::accept()
 
 void SettingsDialog::setInterpolator(int interpolator)
 {
-    const int i = m_ui.interpolate_combo->findData(interpolator);
-    if(i != -1)
+    const int index = m_ui.interpolate_combo->findData(interpolator);
+    if(index != -1)
     {
-        m_ui.interpolate_combo->setCurrentIndex(i);
+        m_ui.interpolate_combo->setCurrentIndex(index);
     }
 }
