Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full replay gain support for track metadata, file tags and library #766

Merged
merged 21 commits into from Nov 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9626401
ReplayGain: Fix confusion between ratio <-> peak
uklotzde Oct 31, 2015
c8e980f
ReplayGain: Fix wrong comment
uklotzde Oct 31, 2015
1a4a252
ReplayGain: Fix parsing of dB gain values
uklotzde Oct 31, 2015
bcb0b07
ReplayGain: Add constants for peak values
uklotzde Oct 31, 2015
15229a4
ReplayGain: Add functions for peak values
uklotzde Oct 31, 2015
8731104
ReplayGain: Parse/format/normalize peak values
uklotzde Oct 31, 2015
358af37
ReplayGain: Add initializing constructor
uklotzde Oct 31, 2015
9fd2a09
Track metadata: Complete replay gain support incl. peak amplitude
uklotzde Oct 31, 2015
00fab0a
DB schema v25: Complete replay gain support incl. peak amplitude
uklotzde Oct 31, 2015
f5f5d4e
ReplayGain: Improve documentation (review comments)
uklotzde Nov 3, 2015
77b8f18
ReplayGain: Prevent subclassing
uklotzde Nov 3, 2015
bc08570
Transform const into constexpr for static assertions
uklotzde Nov 3, 2015
d9f4e35
ReplayGain: Add static assertion for peak amplitude (review comments)
uklotzde Nov 3, 2015
c8511d3
ReplayGain: Rename functions for parsing and formatting (review comme…
uklotzde Nov 3, 2015
10b31ed
ReplayGain: Add test for parsing 0 dB strings
uklotzde Nov 3, 2015
939fb65
Add "Replay Gain" column to browse view
uklotzde Nov 4, 2015
a1beb56
Add "Replay Gain" column to library view
uklotzde Nov 4, 2015
613305c
Re-enable tooltip for calendar year
uklotzde Nov 4, 2015
929649f
Add "Replay Gain" field to track info dialog
uklotzde Nov 4, 2015
72b6c36
Add context menu item for resetting the replay gain
uklotzde Nov 4, 2015
b1f5302
Merge branch 'master' into ReplayGainPeak
uklotzde Nov 7, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions res/schema.xml
Expand Up @@ -395,4 +395,14 @@ METADATA
ALTER TABLE library ADD COLUMN coverart_hash INTEGER DEFAULT 0;
</sql>
</revision>
<revision version="25" min_compatible="3">
<description>
Add full replay gain support including peak amplitude. The default
value for the peak amplitude is "undefined", represented by any
negative value. The internal constant for "undefined" is -1.0.
</description>
<sql>
ALTER TABLE library ADD COLUMN replaygain_peak REAL DEFAULT -1.0;
</sql>
</revision>
</schema>
11 changes: 4 additions & 7 deletions src/analyserrg.cpp
Expand Up @@ -31,8 +31,7 @@ bool AnalyserGain::initialise(TrackPointer tio, int sampleRate, int totalSamples

bool AnalyserGain::loadStored(TrackPointer tio) const {
bool bAnalyserEnabled = (bool)m_pConfigReplayGain->getValueString(ConfigKey("[ReplayGain]","ReplayGainAnalyserEnabled")).toInt();
float fReplayGain = tio->getReplayGain();
if (fReplayGain != 0 || !bAnalyserEnabled) {
if (tio->getReplayGain().hasRatio() || !bAnalyserEnabled) {
return true;
}
return false;
Expand Down Expand Up @@ -76,11 +75,9 @@ void AnalyserGain::finalise(TrackPointer tio) {
return;
}

float fReplayGain_Result = db2ratio(ReplayGainOutput);
Mixxx::ReplayGain replayGain(tio->getReplayGain());
replayGain.setRatio(db2ratio(ReplayGainOutput));
tio->setReplayGain(replayGain);

//qDebug() << "ReplayGain result is" << ReplayGainOutput << "pow:" << fReplayGain_Result;
//qDebug()<<"ReplayGain outputs "<< ReplayGainOutput << "db for track "<< tio->getLocation();
tio->setReplayGain(fReplayGain_Result);
//if(fReplayGain_Result) qDebug() << "ReplayGain Analyser found a ReplayGain value of "<< 20*log10(fReplayGain_Result) << "dB for track " << (tio->getLocation());
m_bStepControl=false;
}
12 changes: 6 additions & 6 deletions src/basetrackplayer.cpp
Expand Up @@ -168,8 +168,8 @@ void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer track, bool bPlay) {
m_pKey, SLOT(slotSet(double)));

// Listen for updates to the file's Replay Gain
connect(m_pLoadedTrack.data(), SIGNAL(ReplayGainUpdated(double)),
this, SLOT(slotSetReplayGain(double)));
connect(m_pLoadedTrack.data(), SIGNAL(ReplayGainUpdated(Mixxx::ReplayGain)),
this, SLOT(slotSetReplayGain(Mixxx::ReplayGain)));
}

// Request a new track from the reader
Expand Down Expand Up @@ -231,7 +231,7 @@ void BaseTrackPlayerImpl::slotFinishLoading(TrackPointer pTrackInfoObject)
m_pDuration->set(m_pLoadedTrack->getDuration());
m_pBPM->slotSet(m_pLoadedTrack->getBpm());
m_pKey->slotSet(m_pLoadedTrack->getKey());
m_pReplayGain->set(m_pLoadedTrack->getReplayGain());
m_pReplayGain->set(m_pLoadedTrack->getReplayGain().getRatio());

// Update the PlayerInfo class that is used in EngineShoutcast to replace
// the metadata of a stream
Expand Down Expand Up @@ -298,19 +298,19 @@ TrackPointer BaseTrackPlayerImpl::getLoadedTrack() const {
return m_pLoadedTrack;
}

void BaseTrackPlayerImpl::slotSetReplayGain(double replayGain) {
void BaseTrackPlayerImpl::slotSetReplayGain(Mixxx::ReplayGain replayGain) {
// Do not change replay gain when track is playing because
// this may lead to an unexpected volume change
if (m_pPlay->get() == 0.0) {
m_pReplayGain->set(replayGain);
m_pReplayGain->set(replayGain.getRatio());
} else {
m_replaygainPending = true;
}
}

void BaseTrackPlayerImpl::slotPlayToggled(double v) {
if (!v && m_replaygainPending) {
m_pReplayGain->set(m_pLoadedTrack->getReplayGain());
m_pReplayGain->set(m_pLoadedTrack->getReplayGain().getRatio());
m_replaygainPending = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/basetrackplayer.h
Expand Up @@ -68,7 +68,7 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer {
void slotFinishLoading(TrackPointer pTrackInfoObject);
void slotLoadFailed(TrackPointer pTrackInfoObject, QString reason);
void slotUnloadTrack(TrackPointer track);
void slotSetReplayGain(double replayGain);
void slotSetReplayGain(Mixxx::ReplayGain replayGain);
void slotPlayToggled(double);

private:
Expand Down
3 changes: 3 additions & 0 deletions src/dlgtrackinfo.cpp
Expand Up @@ -159,6 +159,8 @@ void DlgTrackInfo::populateFields(TrackPointer pTrack) {
txtBitrate->setText(QString(pTrack->getBitrateStr()) + (" ") + tr("kbps"));
txtBpm->setText(pTrack->getBpmStr());
txtKey->setText(pTrack->getKeyText());
const Mixxx::ReplayGain replayGain(pTrack->getReplayGain());
txtReplayGain->setText(Mixxx::ReplayGain::ratioToString(replayGain.getRatio()));
BeatsPointer pBeats = pTrack->getBeats();
bool beatsSupportsSet = !pBeats || (pBeats->getCapabilities() & Beats::BEATSCAP_SET);
bool enableBpmEditing = !pTrack->hasBpmLock() && beatsSupportsSet;
Expand Down Expand Up @@ -434,6 +436,7 @@ void DlgTrackInfo::clear() {
txtLocation->setPlainText("");
txtBitrate->setText("");
txtBpm->setText("");
txtReplayGain->setText("");

m_cueMap.clear();
cueTable->clearContents();
Expand Down
70 changes: 48 additions & 22 deletions src/dlgtrackinfo.ui
Expand Up @@ -473,7 +473,7 @@
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1,1,1,1,1,1,1">
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1,0,1,0,1">
<item row="0" column="0">
<widget class="QLabel" name="lblDuration">
<property name="font">
Expand All @@ -490,6 +490,16 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="txtDuration">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="lblBpm">
<property name="font">
Expand All @@ -506,34 +516,34 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblLocation">
<item row="0" column="3">
<widget class="QLabel" name="txtBpm">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="lblReplayGain">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Location:</string>
<string>Replay Gain:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="txtDuration">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="txtBpm">
<item row="0" column="5">
<widget class="QLabel" name="txtReplayGain">
<property name="text">
<string/>
</property>
Expand All @@ -542,7 +552,7 @@
</property>
</widget>
</item>
<item row="0" column="4">
<item row="1" column="0">
<widget class="QLabel" name="lblBitrate">
<property name="font">
<font>
Expand All @@ -558,7 +568,7 @@
</property>
</widget>
</item>
<item row="0" column="5">
<item row="1" column="1">
<widget class="QLabel" name="txtBitrate">
<property name="text">
<string/>
Expand All @@ -568,7 +578,7 @@
</property>
</widget>
</item>
<item row="0" column="6">
<item row="1" column="2">
<widget class="QLabel" name="lblType">
<property name="font">
<font>
Expand All @@ -584,7 +594,7 @@
</property>
</widget>
</item>
<item row="0" column="7">
<item row="1" column="3">
<widget class="QLabel" name="txtType">
<property name="text">
<string/>
Expand All @@ -594,7 +604,23 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="7">
<item row="2" column="0">
<widget class="QLabel" name="lblLocation">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Location:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="5">
<widget class="QPlainTextEdit" name="txtLocation">
<property name="enabled">
<bool>true</bool>
Expand Down
17 changes: 10 additions & 7 deletions src/library/basesqltablemodel.cpp
Expand Up @@ -105,6 +105,8 @@ void BaseSqlTableModel::initHeaderData() {
tr("Preview"), 50);
setHeaderProperties(ColumnCache::COLUMN_LIBRARYTABLE_COVERART,
tr("Cover Art"), 90);
setHeaderProperties(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN,
tr("Replay Gain"), 50);
}

QSqlDatabase BaseSqlTableModel::database() const {
Expand Down Expand Up @@ -172,7 +174,8 @@ bool BaseSqlTableModel::isColumnHiddenByDefault(int column) {
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_YEAR)) ||
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_GROUPING)) ||
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_LOCATION)) ||
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ALBUMARTIST))) {
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ALBUMARTIST)) ||
(column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN))) {
return true;
}
return false;
Expand Down Expand Up @@ -582,9 +585,7 @@ QVariant BaseSqlTableModel::data(const QModelIndex& index, int role) const {
} else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK)) {
value = value.toBool();
} else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_YEAR)) {
if (Qt::DisplayRole == role) {
value = Mixxx::TrackMetadata::formatCalendarYear(value.toString());
}
value = Mixxx::TrackMetadata::formatCalendarYear(value.toString());
} else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TRACKNUMBER)) {
int track_number = value.toInt();
if (track_number <= 0) {
Expand Down Expand Up @@ -613,8 +614,9 @@ QVariant BaseSqlTableModel::data(const QModelIndex& index, int role) const {
value = KeyUtils::keyToString(key);
}
}
// Otherwise, just use the column value.
}
} else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN)) {
value = Mixxx::ReplayGain::ratioToString(value.toDouble());
} // Otherwise, just use the column value.

break;
case Qt::EditRole:
Expand Down Expand Up @@ -722,7 +724,8 @@ Qt::ItemFlags BaseSqlTableModel::readWriteFlags(
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DURATION) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BITRATE) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DATETIMEADDED) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART)) {
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN)) {
return defaultFlags;
} else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED)) {
return defaultFlags | Qt::ItemIsUserCheckable;
Expand Down
5 changes: 4 additions & 1 deletion src/library/basetrackcache.cpp
Expand Up @@ -307,6 +307,8 @@ void BaseTrackCache::getTrackValueForColumn(TrackPointer pTrack,
trackValue.setValue(pTrack->getBitrate());
} else if (fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM) == column) {
trackValue.setValue(pTrack->getBpm());
} else if (fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN) == column) {
trackValue.setValue(pTrack->getReplayGain().getRatio());
} else if (fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED) == column) {
trackValue.setValue(pTrack->getPlayed());
} else if (fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED) == column) {
Expand Down Expand Up @@ -589,7 +591,8 @@ int BaseTrackCache::compareColumnValues(int sortColumn, Qt::SortOrder sortOrder,
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM) ||
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DURATION) ||
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED) ||
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_RATING)) {
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_RATING) ||
sortColumn == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN)) {
// Sort as floats.
double delta = val1.toDouble() - val2.toDouble();

Expand Down
7 changes: 5 additions & 2 deletions src/library/browse/browsetablemodel.cpp
Expand Up @@ -39,6 +39,7 @@ BrowseTableModel::BrowseTableModel(QObject* parent,
header_data.insert(COLUMN_KEY, tr("Key"));
header_data.insert(COLUMN_TYPE, tr("Type"));
header_data.insert(COLUMN_BITRATE, tr("Bitrate"));
header_data.insert(COLUMN_REPLAYGAIN, tr("Replay Gain"));
header_data.insert(COLUMN_LOCATION, tr("Location"));
header_data.insert(COLUMN_ALBUMARTIST, tr("Album Artist"));
header_data.insert(COLUMN_GROUPING, tr("Grouping"));
Expand Down Expand Up @@ -151,7 +152,8 @@ bool BrowseTableModel::isColumnHiddenByDefault(int column) {
column == COLUMN_GROUPING ||
column == COLUMN_LOCATION ||
column == COLUMN_ALBUMARTIST ||
column == COLUMN_FILE_CREATION_TIME) {
column == COLUMN_FILE_CREATION_TIME ||
column == COLUMN_REPLAYGAIN) {
return true;
}
return false;
Expand Down Expand Up @@ -305,7 +307,8 @@ Qt::ItemFlags BrowseTableModel::flags(const QModelIndex &index) const {
column == COLUMN_DURATION ||
column == COLUMN_TYPE ||
column == COLUMN_FILE_MODIFIED_TIME ||
column == COLUMN_FILE_CREATION_TIME) {
column == COLUMN_FILE_CREATION_TIME ||
column == COLUMN_REPLAYGAIN) {
return defaultFlags;
} else {
return defaultFlags | Qt::ItemIsEditable;
Expand Down
1 change: 1 addition & 0 deletions src/library/browse/browsetablemodel.h
Expand Up @@ -31,6 +31,7 @@ const int COLUMN_ALBUMARTIST = 16;
const int COLUMN_GROUPING = 17;
const int COLUMN_FILE_MODIFIED_TIME = 18;
const int COLUMN_FILE_CREATION_TIME = 19;
const int COLUMN_REPLAYGAIN = 20;


// The BrowseTable models displays tracks
Expand Down
7 changes: 7 additions & 0 deletions src/library/browse/browsethread.cpp
Expand Up @@ -255,6 +255,13 @@ void BrowseThread::populateModel() {
item->setData(creationTime, Qt::UserRole);
row_data.insert(COLUMN_FILE_CREATION_TIME, item);

const Mixxx::ReplayGain replayGain(tio.getReplayGain());
item = new QStandardItem(
Mixxx::ReplayGain::ratioToString(replayGain.getRatio()));
item->setToolTip(item->text());
item->setData(item->text(), Qt::UserRole);
row_data.insert(COLUMN_REPLAYGAIN, item);

rows.append(row_data);
++row;
// If 10 tracks have been analyzed, send it to GUI
Expand Down