TTKMusicPlayer  3.7.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 "ttksemaphoreloop.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  m_ui->volumeLineEdit->setValidator(new QRegExpValidator(QRegExp("-?[0-9]+$"), this));
90 
91  m_ui->progressBar->setStyleSheet(TTK::UI::ProgressBar01);
92  m_ui->progressBarAll->setStyleSheet(TTK::UI::ProgressBar01);
93 
94  m_process = new QProcess(this);
95  m_process->setProcessChannelMode(QProcess::MergedChannels);
96 
97  initialize();
98 
99  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(analysisOutput()));
100  connect(m_ui->addFileButton, SIGNAL(clicked()), SLOT(addFileButtonClicked()));
101  connect(m_ui->addFilesButton, SIGNAL(clicked()), SLOT(addFilesButtonClicked()));
102  connect(m_ui->rmFileButton, SIGNAL(clicked()), SLOT(rmFileButtonClicked()));
103  connect(m_ui->rmFilesButton, SIGNAL(clicked()), SLOT(rmFilesButtonClicked()));
104  connect(m_ui->analysisButton, SIGNAL(clicked()), SLOT(analysisButtonClicked()));
105  connect(m_ui->applyButton, SIGNAL(clicked()), SLOT(applyButtonClicked()));
106  connect(m_ui->volumeLineEdit, SIGNAL(textChanged(QString)), SLOT(lineTextChanged(QString)));
107  connect(m_ui->selectedAreaWidget, SIGNAL(confirmChanged()), SLOT(confirmDataChanged()));
108 }
109 
111 {
112  TTKRemoveSingleWidget(className());
113  delete m_process;
114  delete m_ui;
115 }
116 
118 {
119  QPluginLoader loader;
120  loader.setFileName(TTK::TTKQmmp::pluginPath("Light", "lightreplaygain"));
121  const QObject *obj = loader.instance();
122 
123  LightFactory *factory = nullptr;
124  if(obj && (factory = TTKObjectCast(LightFactory*, obj)))
125  {
126  m_replayGainWidget = factory->create(this);
130  m_ui->replayGainLayout->addWidget(m_replayGainWidget);
131  }
132  else
133  {
134  MusicToastLabel::popup(tr("ReplayGain init error"));
135  }
136 }
137 
138 void MusicReplayGainWidget::addItemFinished(const QString &track, const QString &album)
139 {
140  if(m_currentIndex >= m_paths.count())
141  {
142  return;
143  }
144 
145  const int row = m_ui->tableWidget->rowCount();
146  m_ui->tableWidget->setRowCount(row + 1);
147  QHeaderView *headerView = m_ui->tableWidget->horizontalHeader();
148 
149  QTableWidgetItem *item = new QTableWidgetItem;
150  item->setToolTip(m_paths[m_currentIndex]);
151  item->setText(TTK::Widget::elidedText(font(), item->toolTip(), Qt::ElideRight, headerView->sectionSize(0) - 15));
152  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
153  m_ui->tableWidget->setItem(row, 0, item);
154 
155  item = new QTableWidgetItem;
156  item->setText(QString::number(GAIN_DEFAULT - track.toDouble()));
157  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
158  m_ui->tableWidget->setItem(row, 1, item);
159 
160  item = new QTableWidgetItem;
161  item->setText(QString::number(m_ui->volumeLineEdit->text().toDouble() - GAIN_DEFAULT + track.toDouble()));
162  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
163  m_ui->tableWidget->setItem(row, 2, item);
164 
165  item = new QTableWidgetItem;
166  item->setText(QString::number(GAIN_DEFAULT - album.toDouble()));
167  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
168  m_ui->tableWidget->setItem(row, 3, item);
169 
170  item = new QTableWidgetItem;
171  item->setText(QString::number(m_ui->volumeLineEdit->text().toDouble() - GAIN_DEFAULT + album.toDouble()));
172  QtItemSetTextAlignment(item, Qt::AlignLeft | Qt::AlignVCenter);
173  m_ui->tableWidget->setItem(row, 4, item);
174 }
175 
177 {
178  m_ui->addFileButton->setEnabled(enabled);
179  m_ui->addFilesButton->setEnabled(enabled);
180  m_ui->rmFileButton->setEnabled(enabled);
181  m_ui->rmFilesButton->setEnabled(enabled);
182  m_ui->analysisButton->setEnabled(enabled);
183  m_ui->applyButton->setEnabled(enabled);
184 }
185 
187 {
188  const QStringList &files = TTK::File::getOpenFileNames(this, "MP3 File(*.mp3)");
189  if(!files.isEmpty())
190  {
191  setControlEnabled(false);
192  const int orcount = m_paths.count();
193 
194  for(const QString &path : qAsConst(files))
195  {
196  if(!m_paths.contains(path))
197  {
198  m_paths << path;
199  }
200  }
201 
202  for(int i = orcount; i < m_paths.count(); ++i)
203  {
204  m_currentIndex = i;
205  TTKSemaphoreLoop loop;
206  connect(m_process, SIGNAL(finished(int)), &loop, SLOT(quit()));
207  m_process->start(MAKE_GAIN_PATH_FULL, {m_paths[i]});
208  loop.exec();
209  }
210  setControlEnabled(true);
211  }
212 }
213 
215 {
216  const QString &path = TTK::File::getExistingDirectory(this);
217  if(!path.isEmpty())
218  {
219  setControlEnabled(false);
220  for(const QFileInfo &fin : TTK::File::fileInfoListByPath(path))
221  {
222  if(TTK_FILE_SUFFIX(fin) == MP3_FILE_SUFFIX && !m_paths.contains(fin.absoluteFilePath()))
223  {
224  m_currentIndex = m_paths.count();
225  m_paths << fin.absoluteFilePath();
226 
227  TTKSemaphoreLoop loop;
228  connect(m_process, SIGNAL(finished(int)), &loop, SLOT(quit()));
229  m_process->start(MAKE_GAIN_PATH_FULL, {m_paths.back()});
230  loop.exec();
231  }
232  }
233  setControlEnabled(true);
234  }
235 }
236 
238 {
239  const int row = m_ui->tableWidget->currentRow();
240  if(row < 0)
241  {
242  MusicToastLabel::popup(tr("Please select one item first"));
243  return;
244  }
245  m_ui->tableWidget->removeRow(row);
246 }
247 
249 {
250  m_paths.clear();
251  m_ui->tableWidget->removeItems();
252  m_currentIndex = -1;
253 }
254 
256 {
258 }
259 
261 {
262  if(m_paths.isEmpty())
263  {
264  MusicToastLabel::popup(tr("Music gain list is empty"));
265  return;
266  }
267 
268  disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(analysisOutput()));
269  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(applyOutput()));
270 
271  setControlEnabled(false);
272  m_ui->progressBarAll->setRange(0, m_ui->tableWidget->rowCount());
273 
274  for(int i = 0; i < m_ui->tableWidget->rowCount(); ++i)
275  {
276  TTKSemaphoreLoop loop;
277  connect(m_process, SIGNAL(finished(int)), &loop, SLOT(quit()));
278  m_process->start(MAKE_GAIN_PATH_FULL, {"-g", m_ui->tableWidget->item(i, 2)->text(), m_paths[i]});
279  m_ui->progressBarAll->setValue(i + 1);
280  loop.exec();
281  }
282 
283  setControlEnabled(true);
285 
286  disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(applyOutput()));
287  connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(analysisOutput()));
288 
289  MusicToastLabel::popup(tr("Music gain finished"));
290 }
291 
292 void MusicReplayGainWidget::lineTextChanged(const QString &text)
293 {
294  const double d = text.toDouble();
295  for(int i = 0; i < m_ui->tableWidget->rowCount(); ++i)
296  {
297  QString v = m_ui->tableWidget->item(i, 1)->text();
298  m_ui->tableWidget->item(i, 2)->setText(QString::number(d - v.toDouble()));
299  v = m_ui->tableWidget->item(i, 3)->text();
300  m_ui->tableWidget->item(i, 4)->setText(QString::number(d - v.toDouble()));
301  }
302 }
303 
305 {
306  QString track, album;
307  while(m_process->canReadLine())
308  {
309  QByteArray data = m_process->readLine();
310  if(data.contains(GAIN_TRACKDB))
311  {
312  data.replace(GAIN_TRACKDB, {});
313  data.replace("\r\n", {});
314  track = QString(data.trimmed());
315  }
316 
317  if(data.contains(GAIN_ALBUMDB))
318  {
319  data.replace(GAIN_ALBUMDB, {});
320  data.replace("\r\n", {});
321  album = QString(data.trimmed());
322  }
323  }
324 
325  if(!track.isEmpty() || !album.isEmpty())
326  {
327  addItemFinished(track, album);
328  }
329 }
330 
332 {
333  while(m_process->canReadLine())
334  {
335  const QByteArray &data = m_process->readLine();
336  if(data.contains("Applying gain change"))
337  {
338  m_ui->progressBar->setValue(40);
339  }
340  else if(data.contains("done"))
341  {
342  m_ui->progressBar->setValue(100);
343  }
344  else
345  {
346  m_ui->progressBar->setValue(80);
347  }
348  }
349 }
350 
352 {
353  const MusicSongList songs(m_ui->selectedAreaWidget->selectedSongItems());
354  for(const MusicSong &song : qAsConst(songs))
355  {
357  {
358  m_replayGainWidget->open(song.path());
359  }
360  }
361 }
362 
364 {
365  if(!QFile::exists(MAKE_GAIN_PATH_FULL))
366  {
367  MusicToastLabel::popup(tr("Lack of plugin file"));
368  return;
369  }
370 
372 }
static constexpr const char * GAIN_ALBUMDB
TTK_MODULE_EXPORT QString getExistingDirectory(QWidget *parent)
void setBackgroundLabel(QLabel *label)
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
The class of the replay gain widget.
Ui::MusicReplayGainWidget * m_ui
int exec(ProcessEventsFlags flags=AllEvents)
#define QtItemSetTextAlignment(p, a)
Item text alignment.
Definition: ttkqtcompat.h:45
static const QString ProgressBar01
ProgressBar.
static constexpr int GAIN_DEFAULT
static const QString HeaderView01
HeadView.
#define MP3_FILE_SUFFIX
Definition: musicobject.h:50
static constexpr const char * GAIN_TRACKDB
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:53
#define TTKRemoveSingleWidget(name)
static const QString PushButtonStyle04
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 MAKE_GAIN_PATH_FULL
Definition: musicobject.h:150
void lineTextChanged(const QString &text)
void setControlEnabled(bool enabled)
static const QString LineEditStyle01
LineEdit.
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:173
The class of the music song info.
Definition: musicsong.h:28
The class of the semaphore event loop.
The class of the moving widget base.
#define TTKObjectCast(x, y)
Definition: ttkqtglobal.h:60