summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Holthuis <jan.holthuis@ruhr-uni-bochum.de>2021-03-05 14:40:35 +0100
committerJan Holthuis <jan.holthuis@ruhr-uni-bochum.de>2021-03-05 14:40:35 +0100
commit20893add4b98176c1ad06df47e0fc922ab5577be (patch)
tree618ba94fa4f971df95b6dcf0f5c95bcac7744da4 /src
parenteff873a190efa9233d33481158af9e31377282c8 (diff)
parent31557b7d6279b5ce59ba79dd970c1b569ea01eab (diff)
Merge branch '2.3' of github.com:mixxxdj/mixxx
Diffstat (limited to 'src')
-rw-r--r--src/analyzer/analyzerbeats.cpp28
-rw-r--r--src/analyzer/analyzerbeats.h4
-rw-r--r--src/controllers/dlgprefcontroller.cpp177
-rw-r--r--src/controllers/dlgprefcontroller.h4
-rw-r--r--src/controllers/midi/portmidicontroller.cpp10
-rw-r--r--src/engine/controls/bpmcontrol.cpp88
-rw-r--r--src/engine/controls/clockcontrol.cpp2
-rw-r--r--src/engine/controls/cuecontrol.cpp2
-rw-r--r--src/engine/controls/loopingcontrol.cpp12
-rw-r--r--src/library/banshee/bansheeplaylistmodel.cpp5
-rw-r--r--src/library/columncache.cpp1
-rw-r--r--src/library/dao/trackdao.cpp4
-rw-r--r--src/library/dlgtrackinfo.cpp20
-rw-r--r--src/library/rekordbox/rekordboxfeature.cpp8
-rw-r--r--src/preferences/dialog/dlgprefbeatsdlg.ui19
-rw-r--r--src/preferences/dialog/dlgprefeqdlg.ui6
-rw-r--r--src/preferences/dialog/dlgprefinterfacedlg.ui6
-rw-r--r--src/preferences/dialog/dlgprefkeydlg.ui19
-rw-r--r--src/preferences/dialog/dlgprefrecorddlg.ui263
-rw-r--r--src/preferences/dialog/dlgprefvinyldlg.ui15
-rw-r--r--src/test/beatgridtest.cpp27
-rw-r--r--src/test/beatmaptest.cpp28
-rw-r--r--src/test/beatstranslatetest.cpp11
-rw-r--r--src/test/bpmcontrol_test.cpp2
-rw-r--r--src/test/enginesynctest.cpp180
-rw-r--r--src/test/portmidicontroller_test.cpp47
-rw-r--r--src/track/beatfactory.cpp43
-rw-r--r--src/track/beatfactory.h11
-rw-r--r--src/track/beatgrid.cpp165
-rw-r--r--src/track/beatgrid.h59
-rw-r--r--src/track/beatmap.cpp430
-rw-r--r--src/track/beatmap.h69
-rw-r--r--src/track/beats.cpp2
-rw-r--r--src/track/beats.h32
-rw-r--r--src/track/track.cpp32
-rw-r--r--src/track/track.h1
-rw-r--r--src/waveform/renderers/waveformwidgetrenderer.cpp19
-rw-r--r--src/waveform/renderers/waveformwidgetrenderer.h1
-rw-r--r--src/widget/wtrackmenu.cpp4
39 files changed, 880 insertions, 976 deletions
diff --git a/src/analyzer/analyzerbeats.cpp b/src/analyzer/analyzerbeats.cpp
index 67dd45d17f..2036e041fa 100644
--- a/src/analyzer/analyzerbeats.cpp
+++ b/src/analyzer/analyzerbeats.cpp
@@ -46,7 +46,7 @@ AnalyzerBeats::AnalyzerBeats(UserSettingsPointer pConfig, bool enforceBpmDetecti
m_iMaxBpm(9999) {
}
-bool AnalyzerBeats::initialize(TrackPointer tio, int sampleRate, int totalSamples) {
+bool AnalyzerBeats::initialize(TrackPointer pTrack, int sampleRate, int totalSamples) {
if (totalSamples == 0) {
return false;
}
@@ -58,7 +58,7 @@ bool AnalyzerBeats::initialize(TrackPointer tio, int sampleRate, int totalSample
return false;
}
- bool bpmLock = tio->isBpmLocked();
+ bool bpmLock = pTrack->isBpmLocked();
if (bpmLock) {
qDebug() << "Track is BpmLocked: Beat calculation will not start";
return false;
@@ -106,8 +106,7 @@ bool AnalyzerBeats::initialize(TrackPointer tio, int sampleRate, int totalSample
m_iCurrentSample = 0;
// if we can load a stored track don't reanalyze it
- bool bShouldAnalyze = shouldAnalyze(tio);
-
+ bool bShouldAnalyze = shouldAnalyze(pTrack);
DEBUG_ASSERT(!m_pPlugin);
if (bShouldAnalyze) {
@@ -136,11 +135,11 @@ bool AnalyzerBeats::initialize(TrackPointer tio, int sampleRate, int totalSample
return bShouldAnalyze;
}
-bool AnalyzerBeats::shouldAnalyze(TrackPointer tio) const {
+bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const {
int iMinBpm = m_bpmSettings.getBpmRangeStart();
int iMaxBpm = m_bpmSettings.getBpmRangeEnd();
- bool bpmLock = tio->isBpmLocked();
+ bool bpmLock = pTrack->isBpmLocked();
if (bpmLock) {
qDebug() << "Track is BpmLocked: Beat calculation will not start";
return false;
@@ -153,7 +152,7 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer tio) const {
// If the track already has a Beats object then we need to decide whether to
// analyze this track or not.
- mixxx::BeatsPointer pBeats = tio->getBeats();
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
if (!pBeats) {
return true;
}
@@ -221,7 +220,7 @@ void AnalyzerBeats::cleanup() {
m_pPlugin.reset();
}
-void AnalyzerBeats::storeResults(TrackPointer tio) {
+void AnalyzerBeats::storeResults(TrackPointer pTrack) {
VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
return;
}
@@ -237,7 +236,6 @@ void AnalyzerBeats::storeResults(TrackPointer tio) {
QHash<QString, QString> extraVersionInfo = getExtraVersionInfo(
m_pluginId, m_bPreferencesFastAnalysis);
pBeats = BeatFactory::makePreferredBeats(
- *tio,
beats,
extraVersionInfo,
m_bPreferencesFixedTempo,
@@ -251,21 +249,21 @@ void AnalyzerBeats::storeResults(TrackPointer tio) {
} else {
float bpm = m_pPlugin->getBpm();
qDebug() << "AnalyzerBeats plugin detected constant BPM: " << bpm;
- pBeats = BeatFactory::makeBeatGrid(*tio, bpm, 0.0f);
+ pBeats = BeatFactory::makeBeatGrid(m_iSampleRate, bpm, 0.0f);
}
- mixxx::BeatsPointer pCurrentBeats = tio->getBeats();
+ mixxx::BeatsPointer pCurrentBeats = pTrack->getBeats();
// If the track has no beats object then set our newly generated one
// regardless of beat lock.
if (!pCurrentBeats) {
- tio->setBeats(pBeats);
+ pTrack->setBeats(pBeats);
return;
}
// If the track received the beat lock while we were analyzing it then we
// abort setting it.
- if (tio->isBpmLocked()) {
+ if (pTrack->isBpmLocked()) {
qDebug() << "Track was BPM-locked as we were analyzing it. Aborting analysis.";
return;
}
@@ -278,7 +276,7 @@ void AnalyzerBeats::storeResults(TrackPointer tio) {
qDebug() << "Replacing 0-BPM beatgrid with a" << pBeats->getBpm()
<< "beatgrid.";
}
- tio->setBeats(pBeats);
+ pTrack->setBeats(pBeats);
return;
}
@@ -287,7 +285,7 @@ void AnalyzerBeats::storeResults(TrackPointer tio) {
double currentFirstBeat = pCurrentBeats->findNextBeat(0);
double newFirstBeat = pBeats->findNextBeat(0);
if (currentFirstBeat == 0.0 && newFirstBeat > 0) {
- pCurrentBeats->translate(newFirstBeat);
+ pTrack->setBeats(pCurrentBeats->translate(newFirstBeat));
}
}
diff --git a/src/analyzer/analyzerbeats.h b/src/analyzer/analyzerbeats.h
index 1169fd0436..4efb2f3075 100644
--- a/src/analyzer/analyzerbeats.h
+++ b/src/analyzer/analyzerbeats.h
@@ -26,13 +26,13 @@ class AnalyzerBeats : public Analyzer {
static QList<mixxx::AnalyzerPluginInfo> availablePlugins();
static mixxx::AnalyzerPluginInfo defaultPlugin();
- bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
+ bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override;
bool processSamples(const CSAMPLE *pIn, const int iLen) override;
void storeResults(TrackPointer tio) override;
void cleanup() override;
private:
- bool shouldAnalyze(TrackPointer tio) const;
+ bool shouldAnalyze(TrackPointer pTrack) const;
static QHash<QString, QString> getExtraVersionInfo(
const QString& pluginId, bool bPreferencesFastAnalysis);
diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp
index 971253bf95..8120412b53 100644
--- a/src/controllers/dlgprefcontroller.cpp
+++ b/src/controllers/dlgprefcontroller.cpp
@@ -14,6 +14,7 @@
#include "controllers/controllerlearningeventfilter.h"
#include "controllers/controllermanager.h"
#include "controllers/defs_controllers.h"
+#include "controllers/midi/legacymidicontrollermapping.h"
#include "defs_urls.h"
#include "moc_dlgprefcontroller.cpp"
#include "preferences/usersettings.h"
@@ -21,6 +22,13 @@
namespace {
const QString kMappingExt(".midi.xml");
+
+QString mappingNameToPath(const QString& directory, const QString& mappingName) {
+ // While / is allowed for the display name we can't use it for the file name.
+ QString fileName = QString(mappingName).replace(QChar('/'), QChar('-'));
+ return directory + fileName + kMappingExt;
+}
+
} // namespace
DlgPrefController::DlgPrefController(
@@ -134,11 +142,7 @@ DlgPrefController::~DlgPrefController() {
}
void DlgPrefController::showLearningWizard() {
- // If the user has checked the "Enabled" checkbox but they haven't hit OK to
- // apply it yet, prompt them to apply the settings before we open the
- // learning dialog. If we don't apply the settings first and open the
- // device, the dialog won't react to controller messages.
- if (m_ui.chkEnabledDevice->isChecked() && !m_pController->isOpen()) {
+ if (isDirty()) {
QMessageBox::StandardButton result = QMessageBox::question(this,
tr("Apply device settings?"),
tr("Your settings must be applied before starting the learning "
@@ -155,6 +159,11 @@ void DlgPrefController::showLearningWizard() {
}
slotApply();
+ if (!m_pMapping) {
+ m_pMapping = std::shared_ptr<LegacyControllerMapping>(new LegacyMidiControllerMapping());
+ emit applyMapping(m_pController, m_pMapping, true);
+ }
+
// Note that DlgControllerLearning is set to delete itself on close using
// the Qt::WA_DeleteOnClose attribute (so this "new" doesn't leak memory)
m_pDlgControllerLearning = new DlgControllerLearning(this, m_pController);
@@ -187,7 +196,43 @@ void DlgPrefController::showLearningWizard() {
connect(m_pDlgControllerLearning,
&DlgControllerLearning::stopLearning,
this,
- &DlgPrefController::mappingEnded);
+ &DlgPrefController::slotStopLearning);
+}
+
+void DlgPrefController::slotStopLearning() {
+ VERIFY_OR_DEBUG_ASSERT(m_pMapping) {
+ emit mappingEnded();
+ return;
+ }
+
+ applyMappingChanges();
+ if (m_pMapping->filePath().isEmpty()) {
+ // This mapping was created when the learning wizard was started
+ if (m_pMapping->isDirty()) {
+ QString mappingName = askForMappingName();
+ QString mappingPath = mappingNameToPath(m_pUserDir, mappingName);
+ m_pMapping->setName(mappingName);
+ if (m_pMapping->saveMapping(mappingPath)) {
+ qDebug() << "Mapping saved as" << mappingPath;
+ m_pMapping->setFilePath(mappingPath);
+ m_pMapping->setDirty(false);
+ emit applyMapping(m_pController, m_pMapping, true);
+ enumerateMappings(mappingPath);
+ } else {
+ qDebug() << "Failed to save mapping as" << mappingPath;
+ // Discard the new mapping and disable the controller
+ m_pMapping.reset();
+ emit applyMapping(m_pController, m_pMapping, false);
+ }
+ } else {
+ // No changes made to the new mapping, discard it and disable the
+ // controller
+ m_pMapping.reset();
+ emit applyMapping(m_pController, m_pMapping, false);
+ }
+ }
+
+ emit mappingEnded();
}
void DlgPrefController::midiInputMappingsLearned(
@@ -329,6 +374,7 @@ QString DlgPrefController::mappingFileLinks(
}
void DlgPrefController::enumerateMappings(const QString& selectedMappingPath) {
+ m_ui.comboBoxMapping->blockSignals(true);
m_ui.comboBoxMapping->clear();
// qDebug() << "Enumerating mappings for controller" << m_pController->getName();
@@ -386,6 +432,8 @@ void DlgPrefController::enumerateMappings(const QString& selectedMappingPath) {
m_ui.comboBoxMapping->setCurrentIndex(index);
m_ui.chkEnabledDevice->setEnabled(true);
}
+ m_ui.comboBoxMapping->blockSignals(false);
+ slotMappingSelected(m_ui.comboBoxMapping->currentIndex());
}
MappingInfo DlgPrefController::enumerateMappingsFromEnumerator(
@@ -413,14 +461,14 @@ MappingInfo DlgPrefController::enumerateMappingsFromEnumerator(
}
void DlgPrefController::slotUpdate() {
- enumerateMappings(m_pControllerManager->getConfiguredMappingFileForDevice(
- m_pController->getName()));
-
// Check if the controller is open.
bool deviceOpen = m_pController->isOpen();
// Check/uncheck the "Enabled" box
m_ui.chkEnabledDevice->setChecked(deviceOpen);
+ enumerateMappings(m_pControllerManager->getConfiguredMappingFileForDevice(
+ m_pController->getName()));
+
// If the controller is not mappable, disable the input and output mapping
// sections and the learning wizard button.
bool isMappable = m_pController->isMappable();
@@ -469,6 +517,10 @@ void DlgPrefController::slotApply() {
return;
}
+ QString mappingPath = mappingPathFromIndex(m_ui.comboBoxMapping->currentIndex());
+ m_pMapping = LegacyControllerMappingFileHandler::loadMapping(
+ mappingPath, QDir(resourceMappingsPath(m_pConfig)));
+
// Load the resulting mapping (which has been mutated by the input/output
// table models). The controller clones the mapping so we aren't touching
// the same mapping.
@@ -482,9 +534,18 @@ QUrl DlgPrefController::helpUrl() const {
return QUrl(MIXXX_MANUAL_CONTROLLERS_URL);
}
+QString DlgPrefController::mappingPathFromIndex(int index) const {
+ if (index == 0) {
+ // "No Mapping" item
+ return QString();
+ }
+
+ return m_ui.comboBoxMapping->itemData(index).toString();
+}
+
void DlgPrefController::slotMappingSelected(int chosenIndex) {
- QString mappingPath;
- if (chosenIndex == 0) {
+ QString mappingPath = mappingPathFromIndex(chosenIndex);
+ if (mappingPath.isEmpty()) {
// User picked "No Mapping" item
m_ui.chkEnabledDevice->setEnabled(false);
@@ -500,8 +561,6 @@ void DlgPrefController::slotMappingSelected(int chosenIndex) {
m_ui.chkEnabledDevice->setChecked(true);
setDirty(true);
}
-
- mappingPath = m_ui.comboBoxMapping->itemData(chosenIndex).toString();
}
// Check if the mapping is different from the configured mapping
@@ -595,49 +654,8 @@ void DlgPrefController::saveMapping() {
if (!saveAsNew) {
newFilePath = oldFilePath;
} else {
- QString saveMappingTitle = tr("Save user mapping");
- QString saveMappingLabel = tr("Enter the name for saving the mapping to the user folder.");
- QString savingFailedTitle = tr("Saving mapping failed");
- QString invalidNameLabel =
- tr("A mapping cannot have a blank name and may not contain "
- "special characters.");
- QString fileExistsLabel = tr("A mapping file with that name already exists.");
- // Only allow the name to contain letters, numbers, whitespaces and _-+()/
- const QRegExp rxRemove = QRegExp("[^[(a-zA-Z0-9\\_\\-\\+\\(\\)\\/|\\s]");
-
- // Choose a new file (base) name
- bool validMappingName = false;
- while (!validMappingName) {
- QString userDir = m_pUserDir;
- bool ok = false;
- mappingName = QInputDialog::getText(nullptr,
- saveMappingTitle,
- saveMappingLabel,
- QLineEdit::Normal,
- mappingName,
- &ok)
- .remove(rxRemove)
- .trimmed();
- if (!ok) {
- return;
- }
- if (mappingName.isEmpty()) {
- QMessageBox::warning(nullptr,
- savingFailedTitle,
- invalidNameLabel);
- continue;
- }
- // While / is allowed for the display name we can't use it for the file name.
- QString fileName = mappingName.replace(QString("/"), QString("-"));
- newFilePath = userDir + fileName + kMappingExt;
- if (QFile::exists(newFilePath)) {
- QMessageBox::warning(nullptr,
- savingFailedTitle,
- fileExistsLabel);
- continue;
- }
- validMappingName = true;
- }
+ mappingName = askForMappingName(mappingName);
+ newFilePath = mappingNameToPath(m_pUserDir, mappingName);
m_pMapping->setName(mappingName);
qDebug() << "Mapping renamed to" << m_pMapping->name();
}
@@ -654,6 +672,53 @@ void DlgPrefController::saveMapping() {
enumerateMappings(m_pMapping->filePath());
}
+QString DlgPrefController::askForMappingName(const QString& prefilledName) const {
+ QString saveMappingTitle = tr("Save user mapping");
+ QString saveMappingLabel = tr("Enter the name for saving the mapping to the user folder.");
+ QString savingFailedTitle = tr("Saving mapping failed");
+ QString invalidNameLabel =
+ tr("A mapping cannot have a blank name and may not contain "
+ "special characters.");
+ QString fileExistsLabel = tr("A mapping file with that name already exists.");
+ // Only allow the name to contain letters, numbers, whitespaces and _-+()/
+ const QRegExp rxRemove = QRegExp("[^[(a-zA-Z0-9\\_\\-\\+\\(\\)\\/|\\s]");
+
+ // Choose a new file (base) name
+ bool validMappingName = false;
+ QString mappingName = prefilledName;
+ while (!validMappingName) {
+ QString userDir = m_pUserDir;
+ bool ok = false;
+ mappingName = QInputDialog::getText(nullptr,
+ saveMappingTitle,
+ saveMappingLabel,
+ QLineEdit::Normal,
+ mappingName,
+ &ok)
+ .remove(rxRemove)
+ .trimmed();
+ if (!ok) {
+ continue;
+ }
+ if (mappingName.isEmpty()) {
+ QMessageBox::warning(nullptr,
+ savingFailedTitle,
+ invalidNameLabel);
+ continue;
+ }
+ // While / is allowed for the display name we can't use it for the file name.
+ QString newFilePath = mappingNameToPath(userDir, mappingName);
+ if (QFile::exists(newFilePath)) {
+ QMessageBox::warning(nullptr,
+ savingFailedTitle,
+ fileExistsLabel);
+ continue;
+ }
+ validMappingName = true;
+ }
+ return mappingName;
+}
+
void DlgPrefController::initTableView(QTableView* pTable) {
// Enable selection by rows and extended selection (ctrl/shift click)
pTable->setSelectionBehavior(QAbstractItemView::SelectRows);
diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h
index a277a91317..2bbd47bf01 100644
--- a/src/controllers/dlgprefcontroller.h
+++ b/src/controllers/dlgprefcontroller.h
@@ -51,6 +51,8 @@ class DlgPrefController : public DlgPreferencePage {
/// Used to selected the current mapping in the combobox and display the
/// mapping information.
void slotShowMapping(std::shared_ptr<LegacyControllerMapping> mapping);
+ /// Called when the Controller Learning Wizard is closed.
+ void slotStopLearning();
// Input mappings
void addInputMapping();
@@ -72,6 +74,8 @@ class DlgPrefController : public DlgPreferencePage {
QString mappingDescription(const std::shared_ptr<LegacyControllerMapping> pMapping) const;
QString mappingSupportLinks(const std::shared_ptr<LegacyControllerMapping> pMapping) const;
QString mappingFileLinks(const std::shared_ptr<LegacyControllerMapping> pMapping) const;
+ QString mappingPathFromIndex(int index) const;
+ QString askForMappingName(const QString& prefilledName = QString()) const;
void applyMappingChanges();
void saveMapping();
void initTableView(QTableView* pTable);
diff --git a/src/controllers/midi/portmidicontroller.cpp b/src/controllers/midi/portmidicontroller.cpp
index d7eea579aa..04215af108 100644
--- a/src/controllers/midi/portmidicontroller.cpp
+++ b/src/controllers/midi/portmidicontroller.cpp
@@ -118,16 +118,6 @@ bool PortMidiController::poll() {
return false;
}
- // Returns true if events are available or an error code.
- PmError gotEvents = m_pInputDevice->poll();
- if (gotEvents == FALSE) {
- return false;
- }
- if (gotEvents < 0) {
- qWarning() << "PortMidi error:" << Pm_GetErrorText(gotEvents);
- return false;
- }
-
int numEvents = m_pInputDevice->read(m_midiBuffer, MIXXX_PORTMIDI_BUFFER_LEN);
//qDebug() << "PortMidiController::poll()" << numEvents;
diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp
index 9374bf4950..7e932797e9 100644
--- a/src/engine/controls/bpmcontrol.cpp
+++ b/src/engine/controls/bpmcontrol.cpp
@@ -161,39 +161,67 @@ double BpmControl::getBpm() const {
}
void BpmControl::slotAdjustBeatsFaster(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) {
+ if (v <= 0) {
+ return;
+ }
+ const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) {
double bpm = pBeats->getBpm();
double adjustedBpm = bpm + kBpmAdjustStep;
- pBeats->setBpm(adjustedBpm);
+ pTrack->setBeats(pBeats->setBpm(adjustedBpm));
}
}
void BpmControl::slotAdjustBeatsSlower(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) {
+ if (v <= 0) {
+ return;
+ }
+ const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) {
double bpm = pBeats->getBpm();
double adjustedBpm = math_max(kBpmAdjustMin, bpm - kBpmAdjustStep);
- pBeats->setBpm(adjustedBpm);
+ pTrack->setBeats(pBeats->setBpm(adjustedBpm));
}
}
void BpmControl::slotTranslateBeatsEarlier(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats &&
+ if (v <= 0) {
+ return;
+ }
+ const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats &&
(pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
const double translate_dist = getSampleOfTrack().rate * -.01;
- pBeats->translate(translate_dist);
+ pTrack->setBeats(pBeats->translate(translate_dist));
}
}
void BpmControl::slotTranslateBeatsLater(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats &&
+ if (v <= 0) {
+ return;
+ }
+ const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats &&
(pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
// TODO(rryan): Track::getSampleRate is possibly inaccurate!
const double translate_dist = getSampleOfTrack().rate * .01;
- pBeats->translate(translate_dist);
+ pTrack->setBeats(pBeats->translate(translate_dist));
}
}
@@ -211,11 +239,14 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) {
return;
}
- mixxx::BeatsPointer pBeats = m_pBeats;
+ const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
if (!pBeats) {
return;
}
-
double rateRatio = m_pRateRatio->get();
if (rateRatio == 0.0) {
return;
@@ -224,7 +255,7 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) {
// (60 seconds per minute) * (1000 milliseconds per second) / (X millis per
// beat) = Y beats/minute
double averageBpm = 60.0 * 1000.0 / averageLength / rateRatio;
- pBeats->setBpm(averageBpm);
+ pTrack->setBeats(pBeats->setBpm(averageBpm));
}
void BpmControl::slotControlBeatSyncPhase(double value) {
@@ -590,7 +621,7 @@ bool BpmControl::getBeatContextNoLookup(
double BpmControl::getNearestPositionInPhase(
double dThisPosition, bool respectLoops, bool playing) {
// Without a beatgrid, we don't know the phase offset.
- mixxx::BeatsPointer pBeats = m_pBeats;
+ const mixxx::BeatsPointer pBeats = m_pBeats;
if (!pBeats) {
return dThisPosition;
}
@@ -977,34 +1008,45 @@ void BpmControl::trackBeatsUpdated(mixxx::BeatsPointer pBeats) {
}
void BpmControl::slotBeatsTranslate(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
+ if (v <= 0) {
+ return;
+ }
+ TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
double currentSample = getSampleOfTrack().current;
double closestBeat = pBeats->findClosestBeat(currentSample);
int delta = static_cast<int>(currentSample - closestBeat);
if (delta % 2 != 0) {
delta--;
}
- pBeats->translate(delta);
+ pTrack->setBeats(pBeats->translate(delta));
}
}
void BpmControl::slotBeatsTranslateMatchAlignment(double v) {
- mixxx::BeatsPointer pBeats = m_pBeats;
- if (v > 0 && pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
+ if (v <= 0) {
+ return;
+ }
+ TrackPointer pTrack = getEngineBuffer()->getLoadedTrack();
+ if (!pTrack) {
+ return;
+ }
+ const mixxx::BeatsPointer pBeats = pTrack->getBeats();
+ if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) {
// Must reset the user offset *before* calling getPhaseOffset(),
// otherwise it will always return 0 if master sync is active.
m_dUserOffset.setValue(0.0);
double offset = getPhaseOffset(getSampleOfTrack().current);
- pBeats->translate(-offset);
+ pTrack->setBeats(pBeats->translate(-offset));
}
}
double BpmControl::updateLocalBpm() {
double prev_local_bpm = m_pLocalBpm->get();
double local_bpm = 0;
- mixxx::BeatsPointer pBeats = m_pBeats;
+ const mixxx::BeatsPointer pBeats = m_pBeats;
if (pBeats) {
local_bpm = pBeats->getBpmAroundPosition(
getSampleOfTrack().current, kLocalBpmSpan);
diff --git a/src/engine/controls/clockcontrol.cpp b/src/engine/controls/clockcontrol.cpp
index 22cd4707bc..6dc574ea4b 100644
--- a/src/engine/controls/clockcontrol.cpp
+++ b/src/engine/controls/clockcontrol.cpp
@@ -47,7