summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schürmann <daschuer@mixxx.org>2021-09-26 20:45:54 +0200
committerDaniel Schürmann <daschuer@mixxx.org>2021-09-26 20:45:54 +0200
commit3926fde35a0c5932fd15bb98c150a4c58dc36d92 (patch)
treec1f7ad98a5ca7345098c0d78ceaa195c773a6c71
parent5ed5164586e570374223e0f38ac7056bf3d03fc3 (diff)
parentf4bfce20da6204567870cef57c5a27e6b68f5054 (diff)
Merge remote-tracking branch 'upstream/2.3' into main
-rw-r--r--res/controllers/Denon-MC7000-scripts.js180
-rw-r--r--res/controllers/Denon-MC7000.midi.xml6
-rw-r--r--src/engine/controls/loopingcontrol.cpp23
-rw-r--r--src/engine/enginemaster.cpp2
-rw-r--r--src/engine/sync/enginesync.cpp5
-rw-r--r--src/engine/sync/internalclock.cpp6
6 files changed, 137 insertions, 85 deletions
diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js
index 9381cb9365..16d90ea6ab 100644
--- a/res/controllers/Denon-MC7000-scripts.js
+++ b/res/controllers/Denon-MC7000-scripts.js
@@ -1,5 +1,5 @@
/**
- * Denon DJ MC7000 DJ controller script for Mixxx 2.3
+ * Denon DJ MC7000 DJ controller script for Mixxx 2.3.1
*
* Started in Dec. 2019 by OsZ
*
@@ -41,36 +41,44 @@ MC7000.experimental = false;
// Wanna have Needle Search active while playing a track ?
// In any case Needle Search is available holding "SHIFT" down.
-// can be true or false (recommended: false)
+// can be true or false
MC7000.needleSearchPlay = false;
+// select if the previous sampler shall stop before a new sampler starts
+// true: a running sampler will stop before the new sampler starts
+// false: all triggered samplers will play simultaneously
+MC7000.prevSamplerStop = true;
+
+// Set Vinyl Mode on ("true") or off ("false") when MIXXX starts.
+// This sets the Jog Wheel touch detection / Vinyl Mode
+// and the Jog LEDs ("VINYL" on = spinny, "VINYL" off = track position).
+MC7000.VinylModeOn = true;
+
// Possible pitchfader rate ranges given in percent.
// can be cycled through by the RANGE buttons.
+// All default values are the same as selectable in Mixxx Preferences
MC7000.rateRanges = [
- 4/100, // default: 4/100
- 6/100, // default: 6/100
- 8/100, // default: 8/100
- 10/100, // default: 10/100
- 16/100, // default: 16/100
- 24/100, // default: 24/100
+ 4/100,
+ 6/100,
+ 8/100,
+ 10/100,
+ 16/100,
+ 24/100,
+ 50/100,
+ 90/100,
];
// Platter Ring LED mode
// Mode 0 = Single "off" LED chase (all others "on")
// Mode 1 = Single "on" LED chase (all others "off")
// use "SHIFT" + "DECK #" to toggle between both modes
-MC7000.modeSingleLED = 1; // default: 1
-
-// Set Vinyl Mode on ("true") or off ("false") when MIXXX starts.
-// This sets the Jog Wheel touch detection / Vinyl Mode
-// and the Jog LEDs ("VINYL" on = spinny, "VINYL" off = track position).
-MC7000.VinylModeOn = true; // default: true
+MC7000.modeSingleLED = 1;
// Scratch algorithm parameters
MC7000.scratchParams = {
- recordSpeed: 33 + 1/3, // default: 33 + 1/3
- alpha: (1.0/10), // default: (1.0/10)
- beta: (1.0/10)/32 // default: (1.0/10)/32
+ recordSpeed: 33 + 1/3,
+ alpha: (1.0/10),
+ beta: (1.0/10)/32
};
// Sensitivity factor of the jog wheel (also depends on audio latency)
@@ -78,8 +86,7 @@ MC7000.scratchParams = {
// set to 0.5 with audio buffer set to 50ms
// set to 1 with audio buffer set to 25ms
// set to 3 with audio buffer set to 5ms
-
-MC7000.jogSensitivity = 1; // default: 1.0 with audio buffer set to 23ms
+MC7000.jogSensitivity = 1;
/*/////////////////////////////////
// USER VARIABLES END //
@@ -99,10 +106,6 @@ MC7000.needleSearchTouched = [true, true, true, true];
// initial value for VINYL mode per Deck (see above for user input)
MC7000.isVinylMode = [MC7000.VinylModeOn, MC7000.VinylModeOn, MC7000.VinylModeOn, MC7000.VinylModeOn];
-// used to keep track of which the rateRange of each slider.
-// value used as an index to MC7000.rateRanges
-MC7000.currentRateRangeIndex = [0, 0, 0, 0];
-
// initialize the "factor" function for Spinback
MC7000.factor = [];
@@ -168,10 +171,9 @@ MC7000.init = function() {
var i;
- // Softtakeover for Pitch Faders
- for (i = 1; i <= 4; i++) {
- engine.softTakeover("[Channel" + i + "]", "rate", true);
- }
+ // obtain all knob and slider positions
+ var ControllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7];
+ midi.sendSysexMsg(ControllerStatusSysex, ControllerStatusSysex.length);
// VU meters
engine.makeConnection("[Channel1]", "VuMeter", MC7000.VuMeter);
@@ -211,14 +213,13 @@ MC7000.init = function() {
engine.makeConnection("[Sampler"+i+"]", "play", MC7000.SamplerLED);
}
- // send Controller Status SysEx message delayed to avoid conflicts with Softtakeover
- engine.beginTimer(2000, MC7000.delayedSysEx, true);
-};
-
-// SysEx message to receive all knob and fader positions
-MC7000.delayedSysEx = function() {
- var ControllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7];
- midi.sendSysexMsg(ControllerStatusSysex, ControllerStatusSysex.length);
+ // send Softtakeover delayed to avoid conflicts with ControllerStatusSysex
+ engine.beginTimer(2000, function() {
+ // Softtakeover for Pitch Faders only
+ for (i = 1; i <= 4; i++) {
+ engine.softTakeover("[Channel" + i + "]", "rate", true);
+ }
+ }, true);
};
// Sampler Volume Control
@@ -496,12 +497,17 @@ MC7000.PadButtons = function(channel, control, value, status, group) {
// activate and clear Hot Cues
if (MC7000.PADModeCue[deckNumber] && engine.getValue(group, "track_loaded") === 1) {
for (i = 1; i <= 8; i++) {
- if (control === 0x14 + i - 1 && value >= 0x01) {
+ if (control === 0x14 + i - 1 && value === 0x7F) {
engine.setValue(group, "hotcue_" + i + "_activate", true);
- } else {
+ } else if (control === 0x14 + i - 1 && value === 0x00) {
engine.setValue(group, "hotcue_" + i + "_activate", false);
- }
- if (control === 0x1C + i - 1 && value >= 0x01) {
+ if (engine.getValue(group, "slip_enabled")) {
+ engine.setValue(group, "slip_enabled", false);
+ engine.beginTimer(50, function() {
+ engine.setValue(group, "slip_enabled", true);
+ }, true);
+ }
+ } else if (control === 0x1C + i - 1 && value === 0x7F) {
engine.setValue(group, "hotcue_" + i + "_clear", true);
midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueoff);
}
@@ -562,6 +568,13 @@ MC7000.PadButtons = function(channel, control, value, status, group) {
if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 0) {
engine.setValue("[Sampler" + i + "]", "LoadSelectedTrack", 1);
} else if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 1) {
+ if (MC7000.prevSamplerStop) {
+ // stop playing all other samplers ...
+ for (j = 1; j <=8; j++) {
+ engine.setValue("[Sampler" + j + "]", "cue_gotoandstop", 1);
+ }
+ }
+ // ... before the actual sampler to play gets started
engine.setValue("[Sampler" + i + "]", "cue_gotoandplay", 1);
}
} else if (control === 0x1C + i - 1 && value >= 0x01) {
@@ -640,14 +653,23 @@ MC7000.loadButton = function(channel, control, value, status, group) {
MC7000.wheelTouch = function(channel, control, value, status, group) {
var deckNumber = script.deckFromGroup(group);
var deckOffset = deckNumber - 1;
- if (MC7000.isVinylMode[deckOffset]) {
+ var libraryMaximized = engine.getValue("[Master]", "maximize_library") > 0;
+ if (MC7000.isVinylMode[deckOffset] && !libraryMaximized) {
if (value === 0x7F) {
engine.scratchEnable(deckNumber, MC7000.jogWheelTicksPerRevolution,
MC7000.scratchParams.recordSpeed,
MC7000.scratchParams.alpha,
MC7000.scratchParams.beta);
} else {
- engine.scratchDisable(deckNumber);
+ if (engine.getValue(group, "slip_enabled")) {
+ engine.scratchDisable(deckNumber, false); // stops scratching immediately
+ engine.setValue(group, "slip_enabled", false);
+ engine.beginTimer(50, function() {
+ engine.setValue(group, "slip_enabled", true);
+ }, true);
+ } else {
+ engine.scratchDisable(deckNumber); // continues scratching e.g. for backspin
+ }
}
}
};
@@ -659,22 +681,25 @@ MC7000.wheelTurn = function(channel, control, value, status, group) {
// A: For a control that centers on 0:
var numTicks = (value < 0x64) ? value : (value - 128);
- var adjustedSpeed = numTicks * MC7000.jogSensitivity * 25;
+ var adjustedSpeed = numTicks * MC7000.jogSensitivity / 10;
var deckNumber = script.deckFromGroup(group);
var deckOffset = deckNumber - 1;
- if (engine.isScratching(deckNumber)) {
+ var libraryMaximized = engine.getValue("[Master]", "maximize_library");
+ if (libraryMaximized === 1 && numTicks > 0) {
+ engine.setValue("[Library]", "MoveDown", 1);
+ } else if (libraryMaximized === 1 && numTicks < 0) {
+ engine.setValue("[Library]", "MoveUp", 1);
+ } else if (engine.isScratching(deckNumber)) {
// Scratch!
engine.scratchTick(deckNumber, numTicks * MC7000.jogSensitivity);
} else {
if (MC7000.shift[deckOffset]) {
// While Shift Button pressed -> Search through track
- var jogSearch = 300 * adjustedSpeed / MC7000.jogWheelTicksPerRevolution;
+ var jogSearch = 100 * adjustedSpeed; // moves 100 times faster than normal jog
engine.setValue(group, "jog", jogSearch);
} else {
// While Shift Button released -> Pitch Bend
- var jogDelta = adjustedSpeed / MC7000.jogWheelTicksPerRevolution;
- var jogAbsolute = jogDelta + engine.getValue(group, "jog");
- engine.setValue(group, "jog", jogAbsolute);
+ engine.setValue(group, "jog", adjustedSpeed);
}
}
};
@@ -729,13 +754,17 @@ MC7000.nextRateRange = function(midichan, control, value, status, group) {
if (value === 0) {
return; // don't respond to note off messages
}
- var deckOffset = script.deckFromGroup(group) - 1;
- // increment currentRateRangeIndex and check for overflow
- if (++MC7000.currentRateRangeIndex[deckOffset] ===
- MC7000.rateRanges.length) {
- MC7000.currentRateRangeIndex[deckOffset] = 0;
+ var currRateRange = engine.getValue(group, "rateRange");
+ engine.setValue(group, "rateRange", MC7000.getNextRateRange(currRateRange));
+};
+
+MC7000.getNextRateRange = function(currRateRange) {
+ for (var i = 0; i < MC7000.rateRanges.length; i++) {
+ if (MC7000.rateRanges[i] > currRateRange) {
+ return MC7000.rateRanges[i];
+ }
}
- engine.setValue(group, "rateRange", MC7000.rateRanges[MC7000.currentRateRangeIndex[deckOffset]]);
+ return MC7000.rateRanges[0];
};
// Previous Rate range toggle
@@ -743,12 +772,17 @@ MC7000.prevRateRange = function(midichan, control, value, status, group) {
if (value === 0) {
return; // don't respond to note off messages
}
- var deckOffset = script.deckFromGroup(group) - 1;
- // decrement currentRateRangeIndex and check for underflow
- if (--MC7000.currentRateRangeIndex[deckOffset] < 0) {
- MC7000.currentRateRangeIndex[deckOffset] = MC7000.rateRanges.length - 1;
+ var currRateRange = engine.getValue(group, "rateRange");
+ engine.setValue(group, "rateRange", MC7000.getPrevRateRange(currRateRange));
+};
+
+MC7000.getPrevRateRange = function(currRateRange) {
+ for (var i = MC7000.rateRanges.length; i >= 0; i--) {
+ if (MC7000.rateRanges[i] < currRateRange) {
+ return MC7000.rateRanges[i];
+ }
}
- engine.setValue(group, "rateRange", MC7000.rateRanges[MC7000.currentRateRangeIndex[deckOffset]]);
+ return MC7000.rateRanges[MC7000.rateRanges.length - 1];
};
// Key & Waveform zoom Select
@@ -811,10 +845,19 @@ MC7000.reverse = function(channel, control, value, status, group) {
var deckNumber = script.deckFromGroup(group);
if (value > 0) {
// while the button is pressed spin back
- engine.brake(deckNumber, true, MC7000.factor[deckNumber], - 15); // start at a rate of -15 and decrease by "factor"
+ // start at a rate of -10 and decrease by "MC7000.factor"
+ engine.brake(deckNumber, true, MC7000.factor[deckNumber], -10);
} else {
- // when releasing the button the track starts softly again
- engine.softStart(deckNumber, true, MC7000.factor[deckNumber]);
+ if (engine.getValue(group, "slip_enabled")) {
+ engine.brake(deckNumber, false); // disable brake effect
+ engine.setValue(group, "play", 1);
+ engine.setValue(group, "slip_enabled", false);
+ engine.beginTimer(50, function() {
+ engine.setValue(group, "slip_enabled", true);
+ }, true);
+ } else {
+ engine.softStart(deckNumber, true, MC7000.factor[deckNumber]);
+ }
}
};
@@ -827,6 +870,9 @@ MC7000.censor = function(channel, control, value, status, group) {
} else {
engine.setValue(group, "reverseroll", 0);
}
+ engine.beginTimer(50, function() {
+ engine.setValue(group, "slip_enabled", true);
+ }, true);
} else {
// reverse play while button pressed
if (value > 0) {
@@ -928,14 +974,14 @@ MC7000.TrackPositionLEDs = function(value, group) {
}
// now chose which PAD LED to turn on (+8 means shifted PAD LEDs)
if (beatCountLED === 0) {
- midi.sendShortMsg(0x94 + deckOffset, 0x14, MC7000.padColor.hotcueon);
- midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8, MC7000.padColor.hotcueon);
+ midi.sendShortMsg(0x94 + deckOffset, 0x14, MC7000.padColor.slicerJumpFwd);
+ midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8, MC7000.padColor.slicerJumpFwd);
} else if (beatCountLED === 7) {
- midi.sendShortMsg(0x94 + deckOffset, 0x1B, MC7000.padColor.hotcueon);
- midi.sendShortMsg(0x94 + deckOffset, 0x1B + 8, MC7000.padColor.hotcueon);
+ midi.sendShortMsg(0x94 + deckOffset, 0x1B, MC7000.padColor.slicerJumpFwd);
+ midi.sendShortMsg(0x94 + deckOffset, 0x1B + 8, MC7000.padColor.slicerJumpFwd);
} else if (beatCountLED > 0 && beatCountLED < 7) {
- midi.sendShortMsg(0x94 + deckOffset, 0x14 + beatCountLED, MC7000.padColor.hotcueon);
- midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8 + beatCountLED, MC7000.padColor.hotcueon);
+ midi.sendShortMsg(0x94 + deckOffset, 0x14 + beatCountLED, MC7000.padColor.slicerJumpFwd);
+ midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8 + beatCountLED, MC7000.padColor.slicerJumpFwd);
}
}
MC7000.prevPadLED[deckOffset] = beatCountLED;
diff --git a/res/controllers/Denon-MC7000.midi.xml b/res/controllers/Denon-MC7000.midi.xml
index 1f661b723b..fa66ed534f 100644
--- a/res/controllers/Denon-MC7000.midi.xml
+++ b/res/controllers/Denon-MC7000.midi.xml
@@ -1,9 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
-<MixxxControllerPreset mixxxVersion="2.3" schemaVersion="1">
+<MixxxControllerPreset mixxxVersion="2.3.1" schemaVersion="1">
<info>
<name>Denon MC7000</name>
<author>OsZ</author>
- <description>Denon MC7000 mapping. Check your Linux Kernel version to get the Audio Interface working - see WIKI</description>
+ <description>A professional 4-channel DJ controller featuring 2 separate audio interfaces. Please refer to the Mixxx user manual to get the audio interfaces working on Linux.</description>
<forums>https://mixxx.discourse.group/t/denon-mc7000-mapping/18235</forums>
<wiki>https://github.com/mixxxdj/mixxx/wiki/Denon-MC7000</wiki>
<manual>denon_mc7000</manual>
@@ -939,7 +939,7 @@
<Script-Binding/>
</options>
</control>
- <control>
+ <control>
<group>[Channel1]</group>
<key>MC7000.wheelTouch</key>
<description>MIDI Learned from 759 messages.</description>
diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp
index d663f20e4d..2f449e5df2 100644
--- a/src/engine/controls/loopingcontrol.cpp
+++ b/src/engine/controls/loopingcontrol.cpp
@@ -1535,24 +1535,33 @@ mixxx::audio::FramePos LoopingControl::seekInsideAdjustedLoop(
const mixxx::audio::FrameDiff_t newLoopSize = newLoopEndPosition - newLoopStartPosition;
DEBUG_ASSERT(newLoopSize > 0);
mixxx::audio::FramePos adjustedPosition = currentPosition;
- while (adjustedPosition > newLoopEndPosition) {
- adjustedPosition -= newLoopSize;
+ if (adjustedPosition > newLoopEndPosition) {
+ // In case play head has already passed the new out position, seek in whole
+ // loop size steps back, as if playback has been looped within the boundaries
+ double adjustSteps =
+ ceil((adjustedPosition.value() - newLoopEndPosition.value()) /
+ newLoopSize);
+ adjustedPosition -= adjustSteps * newLoopSize;
+ DEBUG_ASSERT(adjustedPosition <= newLoopEndPosition);
VERIFY_OR_DEBUG_ASSERT(adjustedPosition > newLoopStartPosition) {
// I'm not even sure this is possible. The new loop would have to be bigger than the
// old loop, and the playhead was somehow outside the old loop.
qWarning() << "SHOULDN'T HAPPEN: seekInsideAdjustedLoop couldn't find a new position --"
<< " seeking to in point";
adjustedPosition = newLoopStartPosition;
- break;
}
- }
- while (adjustedPosition < newLoopStartPosition) {
- adjustedPosition += newLoopSize;
+ } else if (adjustedPosition < newLoopStartPosition) {
+ // In case play head has already been looped back to the old loop in position,
+ // seek in whole loop size steps forward until we are in the new loop boundaries
+ double adjustSteps =
+ ceil((newLoopStartPosition.value() - adjustedPosition.value()) /
+ newLoopSize);
+ adjustedPosition += adjustSteps * newLoopSize;
+ DEBUG_ASSERT(adjustedPosition >= newLoopStartPosition);
VERIFY_OR_DEBUG_ASSERT(adjustedPosition < newLoopEndPosition) {
qWarning() << "SHOULDN'T HAPPEN: seekInsideAdjustedLoop couldn't find a new position --"
<< " seeking to in point";
adjustedPosition = newLoopStartPosition;
- break;
}
}
if (adjustedPosition != currentPosition) {
diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp
index 6a446093a9..c8267451cb 100644
--- a/src/engine/enginemaster.cpp
+++ b/src/engine/enginemaster.cpp
@@ -83,7 +83,7 @@ EngineMaster::EngineMaster(
// The last-used bpm value is saved in the destructor of EngineSync.
double default_bpm = pConfig->getValue(
ConfigKey("[InternalClock]", "bpm"), 124.0);
- ControlObject::getControl(ConfigKey("[InternalClock]","bpm"))->set(default_bpm);
+ ControlObject::set(ConfigKey("[InternalClock]", "bpm"), default_bpm);
// Crossfader
m_pCrossfader = new ControlPotmeter(ConfigKey(group, "crossfader"), -1., 1.);
diff --git a/src/engine/sync/enginesync.cpp b/src/engine/sync/enginesync.cpp
index cda9d12f53..e2caf7c8d5 100644
--- a/src/engine/sync/enginesync.cpp
+++ b/src/engine/sync/enginesync.cpp
@@ -26,9 +26,8 @@ EngineSync::EngineSync(UserSettingsPointer pConfig)
EngineSync::~EngineSync() {
// We use the slider value because that is never set to 0.0.
const mixxx::Bpm bpm = m_pInternalClock->getBpm();
- m_pConfig->set(ConfigKey(kInternalClockGroup, "bpm"),
- ConfigValue(
- bpm.isValid() ? bpm.value() : mixxx::Bpm::kValueUndefined));
+ m_pConfig->setValue(ConfigKey(kInternalClockGroup, "bpm"),
+ bpm.isValid() ? bpm.value() : mixxx::Bpm::kValueUndefined);
delete m_pInternalClock;
}
diff --git a/src/engine/sync/internalclock.cpp b/src/engine/sync/internalclock.cpp
index b81152c90d..947bab0b6a 100644
--- a/src/engine/sync/internalclock.cpp
+++ b/src/engine/sync/internalclock.cpp
@@ -9,6 +9,7 @@
#include "moc_internalclock.cpp"
#include "preferences/usersettings.h"
#include "util/logger.h"
+#include "util/math.h"
namespace {
const mixxx::Logger kLogger("InternalClock");
@@ -232,10 +233,7 @@ void InternalClock::onCallbackEnd(mixxx::audio::SampleRate sampleRate, int buffe
m_dBeatLength = 21338;
}
- while (m_dClockPosition >= m_dBeatLength) {
- m_dClockPosition -= m_dBeatLength;
- }
-
+ m_dClockPosition = fmod(m_dClockPosition, m_dBeatLength);
double beatDistance = getBeatDistance();
m_pClockBeatDistance->set(beatDistance);
m_pEngineSync->notifyBeatDistanceChanged(this, beatDistance);