TTKMusicPlayer  4.3.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musicreplaygainwidget.cpp
Go to the documentation of this file.
2 #include "ui_musicreplaygainwidget.h"
3 #include "musicfileutils.h"
4 #include "musicwidgetheaders.h"
5 #include "musicqmmputils.h"
6 #include "musictoastlabel.h"
7 #include "ttkeventloop.h"
8 
9 #include <QProcess>
10 #include <QPluginLoader>
11 
12 #include <qmmp/lightfactory.h>
13 
14 static constexpr int GAIN_DEFAULT = 89;
15 static constexpr const char *GAIN_TRACKDB = "Recommended \"Track\" dB change:";
16 static constexpr const char *GAIN_ALBUMDB = "Recommended \"Album\" dB change for all files:";
17 
19  : MusicAbstractTableWidget(parent)
20 {
21  setColumnCount(5);
22 
23  QHeaderView *headerView = horizontalHeader();
24  headerView->resizeSection(0, 332);
25  headerView->resizeSection(1, 60);
26  headerView->resizeSection(2, 60);
27  headerView->resizeSection(3, 60);
28  headerView->resizeSection(4, 60);
29 }
30 
31 
32 
34  : MusicAbstractMoveWidget(parent),
35  m_ui(new Ui::MusicReplayGainWidget),
36  m_replayGainWidget(nullptr),
37  m_currentIndex(-1)
38 {
39  m_ui->setupUi(this);
40  setFixedSize(size());
41  setAttribute(Qt::WA_DeleteOnClose);
42  setBackgroundLabel(m_ui->background);
43 
44  m_ui->topTitleCloseButton->setIcon(QIcon(":/functions/btn_close_hover"));
45  m_ui->topTitleCloseButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
46  m_ui->topTitleCloseButton->setCursor(QCursor(Qt::PointingHandCursor));
47  m_ui->topTitleCloseButton->setToolTip(tr("Close"));
48  connect(m_ui->topTitleCloseButton, SIGNAL(clicked()), SLOT(close()));
49 
50  m_ui->mainViewWidget->setStyleSheet(TTK::UI::TabWidgetStyle01);
51 
52  m_ui->addFileButton->setIcon(QIcon(":/toolSets/btn_gain_add_file"));
53  m_ui->addFileButton->setIconSize(QSize(40, 40));
54  m_ui->addFileButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
55  m_ui->addFileButton->setToolTip(tr("Add File"));
56  m_ui->addFileButton->setCursor(QCursor(Qt::PointingHandCursor));
57 
58  m_ui->addFilesButton->setIcon(QIcon(":/toolSets/btn_gain_add_files"));
59  m_ui->addFilesButton->setIconSize(QSize(40, 40));
60  m_ui->addFilesButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
61  m_ui->addFilesButton->setToolTip(tr("Add Files"));
62  m_ui->addFilesButton->setCursor(QCursor(Qt::PointingHandCursor));
63 
64  m_ui->rmFileButton->setIcon(QIcon(":/toolSets/btn_gain_rm_file"));
65  m_ui->rmFileButton->setIconSize(QSize(40, 40));
66  m_ui->rmFileButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
67  m_ui->rmFileButton->setToolTip(tr("Remove File"));
68  m_ui->rmFileButton->setCursor(QCursor(Qt::PointingHandCursor));
69 
70  m_ui->rmFilesButton->setIcon(QIcon(":/toolSets/btn_gain_rm_files"));
71  m_ui->rmFilesButton->setIconSize(QSize(40, 40));
72  m_ui->rmFilesButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
73  m_ui->rmFilesButton->setToolTip(tr("Remove Files"));
74  m_ui->rmFilesButton->setCursor(QCursor(Qt::PointingHandCursor));
75 
76  m_ui->analysisButton->setIcon(QIcon(":/toolSets/btn_analysis"));
77  m_ui->analysisButton->setIconSize(QSize(40, 40));
78  m_ui->analysisButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
79  m_ui->analysisButton->setToolTip(tr("Analysis"));
80  m_ui->analysisButton->setCursor(QCursor(Qt::PointingHandCursor));
81 
82  m_ui->applyButton->setIcon(QIcon(":/toolSets/btn_analysis_apply"));
83  m_ui->applyButton->setIconSize(QSize(50, 50));
84  m_ui->applyButton->setStyleSheet(TTK::UI::ToolButtonStyle04);
85  m_ui->applyButton->setToolTip(tr("Apply"));
86  m_ui->applyButton->setCursor(QCursor(Qt::PointingHandCursor));
87 
88  m_ui->volumeLineEdit->setStyleSheet(TTK::UI::LineEditStyle01);
89 #if TTK_QT_VERSION_CHECK(5,1,0)
90  m_ui->volumeLineEdit->setValidator(new QRegularExpressionValidator(QRegularExpression("-?[0-9]+$"), this));
91 #else
92  m_ui->volumeLineEdit->setValidator(new QRegExpValidator(QRegExp("-?[0-9]+$"), this));
93 #endif
94 
95  m_ui->progressBar->setStyleSheet(TTK::UI::ProgressBar01);
96  m_ui->progressBarAll->setStyleSheet(TTK::UI::ProgressBar01);
97 
98  m_process = new QProcess(this);
99  m_process->setProcessChannelMode(QProcess::MergedChannels);
100 
101  initialize();
102 
103  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(analysisOutput()));
104  connect(m_ui->addFileButton, SIGNAL(clicked()), SLOT(addFileButtonClicked()));
105  connect(m_ui->addFilesButton, SIGNAL(clicked()), SLOT(addFilesButtonClicked()));
106  connect(m_ui->rmFileButton, SIGNAL(clicked()), SLOT(rmFileButtonClicked()));
107  connect(m_ui->rmFilesButton, SIGNAL(clicked()), SLOT(rmFilesButtonClicked()));
108  connect(m_ui->analysisButton, SIGNAL(clicked()), SLOT(analysisButtonClicked()));
109  connect(m_ui->applyButton, SIGNAL(clicked()), SLOT(applyButtonClicked()));
110  connect(m_ui->volumeLineEdit, SIGNAL(textChanged(QString)), SLOT(lineTextChanged(QString)));
111  connect(m_ui->selectedAreaWidget, SIGNAL(confirmChanged()), SLOT(confirmDataChanged()));
112 }
113 
115 {
117  delete m_process;
118  delete m_ui;
119 }
120 
122 {
123  QPluginLoader loader;
124  loader.setFileName(TTK::TTKQmmp::pluginPath("Light", "lightreplaygain"));
125  QObject *obj = loader.instance();
126 
127  LightFactory *factory = nullptr;
128  if(obj && (factory = TTKObjectCast(LightFactory*, obj)))
129  {
130  m_replayGainWidget = factory->create(this);
134  m_ui->replayGainLayout->addWidget(m_replayGainWidget);
135  }
136  else
137  {
138  MusicToastLabel::popup(tr("ReplayGain init error"));
139  }
140 }
141 
142 void MusicReplayGainWidget::addItemFinished(const QString &track, const QString &album)
143 {
144  if(m_currentIndex >= m_paths.count())
145  {
146  return;
147  }
148 
149  const int row = m_ui->tableWidget->rowCount();
150  m_ui->tableWidget->setRowCount(row + 1);
151  QHeaderView *headerView = m_ui->tableWidget->horizontalHeader();
152 
153  QTableWidgetItem *item = new QTableWidgetItem;
154  item->setToolTip(m_paths[m_currentIndex]);
155  item->setText(TTK::Widget::elidedText(font(), item->toolTip(), Qt::ElideRight, headerView->sectionSize(0) - 15));
156  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
157  m_ui->tableWidget->setItem(row, 0, item);
158 
159  item = new QTableWidgetItem;
160  item->setText(QString::number(GAIN_DEFAULT - track.toDouble()));
161  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
162  m_ui->tableWidget->setItem(row, 1, item);
163 
164  item = new QTableWidgetItem;
165  item->setText(QString::number(m_ui->volumeLineEdit->text().toDouble() - GAIN_DEFAULT + track.toDouble()));
166  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
167  m_ui->tableWidget->setItem(row, 2, item);
168 
169  item = new QTableWidgetItem;
170  item->setText(QString::number(GAIN_DEFAULT - album.toDouble()));
171  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
172  m_ui->tableWidget->setItem(row, 3, item);
173 
174  item = new QTableWidgetItem;
175  item->setText(QString::number(m_ui->volumeLineEdit->text().toDouble() - GAIN_DEFAULT + album.toDouble()));
176  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
177  m_ui->tableWidget->setItem(row, 4, item);
178 }
179 
181 {
182  m_ui->addFileButton->setEnabled(enabled);
183  m_ui->addFilesButton->setEnabled(enabled);
184  m_ui->rmFileButton->setEnabled(enabled);
185  m_ui->rmFilesButton->setEnabled(enabled);
186  m_ui->analysisButton->setEnabled(enabled);
187  m_ui->applyButton->setEnabled(enabled);
188 }
189 
191 {
192  const QStringList &files = TTK::File::getOpenFileNames(this, "MP3 File(*.mp3)");
193  if(!files.isEmpty())
194  {
195  setControlEnabled(false);
196  const int orcount = m_paths.count();
197 
198  for(const QString &path : qAsConst(files))
199  {
200  if(!m_paths.contains(path))
201  {
202  m_paths << path;
203  }
204  }
205 
206  for(int i = orcount; i < m_paths.count(); ++i)
207  {
208  m_currentIndex = i;
209  TTKEventLoop loop;
212  m_process->start(MAKE_GAIN_PATH_FULL, {m_paths[i]});
213  loop.exec();
214  }
215  setControlEnabled(true);
216  }
217 }
218 
220 {
221  const QString &path = TTK::File::getExistingDirectory(this);
222  if(!path.isEmpty())
223  {
224  setControlEnabled(false);
225  for(const QFileInfo &fin : TTK::File::fileInfoListByPath(path))
226  {
227  if(TTK_FILE_SUFFIX(fin) == MP3_FILE_SUFFIX && !m_paths.contains(fin.absoluteFilePath()))
228  {
229  m_currentIndex = m_paths.count();
230  m_paths << fin.absoluteFilePath();
231 
232  TTKEventLoop loop;
235  m_process->start(MAKE_GAIN_PATH_FULL, {m_paths.last()});
236  loop.exec();
237  }
238  }
239  setControlEnabled(true);
240  }
241 }
242 
244 {
245  const int row = m_ui->tableWidget->currentRow();
246  if(row < 0)
247  {
248  MusicToastLabel::popup(tr("Please select one item first"));
249  return;
250  }
251  m_ui->tableWidget->removeRow(row);
252 }
253 
255 {
256  m_paths.clear();
257  m_ui->tableWidget->removeItems();
258  m_currentIndex = -1;
259 }
260 
262 {
264 }
265 
267 {
268  if(m_paths.isEmpty())
269  {
270  MusicToastLabel::popup(tr("Music gain list is empty"));
271  return;
272  }
273 
274  disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(analysisOutput()));
275  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(applyOutput()));
276 
277  setControlEnabled(false);
278  m_ui->progressBarAll->setRange(0, m_ui->tableWidget->rowCount());
279 
280  for(int i = 0; i < m_ui->tableWidget->rowCount(); ++i)
281  {
282  TTKEventLoop loop;
285  m_process->start(MAKE_GAIN_PATH_FULL, {"-g", m_ui->tableWidget->item(i, 2)->text(), m_paths[i]});
286  m_ui->progressBarAll->setValue(i + 1);
287  loop.exec();
288  }
289 
290  setControlEnabled(true);
292 
293  disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(applyOutput()));
294  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(analysisOutput()));
295 
296  MusicToastLabel::popup(tr("Music gain finished"));
297 }
298 
299 void MusicReplayGainWidget::lineTextChanged(const QString &text)
300 {
301  const double d = text.toDouble();
302  for(int i = 0; i < m_ui->tableWidget->rowCount(); ++i)
303  {
304  QString v = m_ui->tableWidget->item(i, 1)->text();
305  m_ui->tableWidget->item(i, 2)->setText(QString::number(d - v.toDouble()));
306  v = m_ui->tableWidget->item(i, 3)->text();
307  m_ui->tableWidget->item(i, 4)->setText(QString::number(d - v.toDouble()));
308  }
309 }
310 
312 {
313  QString track, album;
314  while(m_process->canReadLine())
315  {
316  QByteArray data = m_process->readLine();
317  if(data.contains(GAIN_TRACKDB))
318  {
319  data.replace(GAIN_TRACKDB, {});
320  data.replace(TTK_WLINEFEED, {});
321  track = QString(data.trimmed());
322  }
323 
324  if(data.contains(GAIN_ALBUMDB))
325  {
326  data.replace(GAIN_ALBUMDB, {});
327  data.replace(TTK_WLINEFEED, {});
328  album = QString(data.trimmed());
329  }
330  }
331 
332  if(!track.isEmpty() || !album.isEmpty())
333  {
334  addItemFinished(track, album);
335  }
336 }
337 
339 {
340  while(m_process->canReadLine())
341  {
342  const QByteArray &data = m_process->readLine();
343  if(data.contains("Applying gain change"))
344  {
345  m_ui->progressBar->setValue(40);
346  }
347  else if(data.contains("done"))
348  {
349  m_ui->progressBar->setValue(100);
350  }
351  else
352  {
353  m_ui->progressBar->setValue(80);
354  }
355  }
356 }
357 
359 {
360  const MusicSongList songs(m_ui->selectedAreaWidget->selectedSongItems());
361  for(const MusicSong &song : qAsConst(songs))
362  {
364  {
365  m_replayGainWidget->open(song.path());
366  }
367  }
368 }
369 
371 {
372  if(!QFile::exists(MAKE_GAIN_PATH_FULL))
373  {
374  MusicToastLabel::popup(tr("Lack of plugin file"));
375  return;
376  }
377 
379 }
static constexpr const char * GAIN_ALBUMDB
TTK_MODULE_EXPORT QString getExistingDirectory(QWidget *parent)
#define QtProcessFinishVoidConnect(p, q, f, s)
Process finished void connect.
Definition: ttkqtcompat.h:108
MusicReplayGainTableWidget(QWidget *parent=nullptr)
Light plugin interface (Light factory).
Definition: lightfactory.h:76
MusicReplayGainWidget(QWidget *parent=nullptr)
The class of the table widget base.
static const QString CheckBoxStyle01
CheckBox.
voidpf void uLong size
Definition: ioapi.h:136
int exec(ProcessEventsFlags flags=AllEvents)
The class of the replay gain widget.
Ui::MusicReplayGainWidget * m_ui
#define QtProcessErrorVoidConnect(p, q, f, s)
Process error void connect.
Definition: ttkqtcompat.h:94
#define QtItemSetTextAlignment(p, a)
Item text alignment.
Definition: ttkqtcompat.h:45
static const QString ProgressBar01
ProgressBar.
static constexpr int GAIN_DEFAULT
void setBackgroundLabel(QLabel *label) noexcept
static const QString HeaderView01
HeadView.
#define MP3_FILE_SUFFIX
Definition: musicobject.h:58
static constexpr const char * GAIN_TRACKDB
The class of the ttk event loop.
Definition: ttkeventloop.h:29
virtual void open(const QString &path)=0
virtual Light * create(QWidget *parent)=0
static void popup(const QString &text)
void addItemFinished(const QString &track, const QString &album)
static const QString ScrollBarStyle03
#define qAsConst
Definition: ttkqtglobal.h:57
static const QString PushButtonStyle04
#define TTK_REMOVE_SINGLE_WIDGET(object)
TTK_MODULE_EXPORT QString elidedText(const QFont &font, const QString &text, Qt::TextElideMode mode, int width)
TTK_MODULE_EXPORT QFileInfoList fileInfoListByPath(const QString &dpath, const QStringList &filter={}, bool recursively=true)
#define TTK_SLOT
Definition: ttkqtglobal.h:177
#define MAKE_GAIN_PATH_FULL
Definition: musicobject.h:169
void lineTextChanged(const QString &text)
void setControlEnabled(bool enabled)
static const QString LineEditStyle01
LineEdit.
#define TTK_WLINEFEED
Definition: ttkglobal.h:272
TTK_MODULE_EXPORT QString pluginPath(const QString &module, const QString &format)
static const QString TabWidgetStyle01
TabWidget.
static const QString ToolButtonStyle04
TTK_MODULE_EXPORT QStringList getOpenFileNames(QWidget *parent, const QString &filter="Image Files (*.png *.bmp *.jpg)")
#define TTK_FILE_SUFFIX(fin)
Definition: ttkqtglobal.h:185
The class of the music song info.
Definition: musicsong.h:28
The class of the moving widget base.
#define TTKObjectCast(x, y)
Definition: ttkqtglobal.h:82