diff options
author | Daniel Schürmann <daschuer@mixxx.org> | 2021-09-26 20:45:54 +0200 |
---|---|---|
committer | Daniel Schürmann <daschuer@mixxx.org> | 2021-09-26 20:45:54 +0200 |
commit | 3926fde35a0c5932fd15bb98c150a4c58dc36d92 (patch) | |
tree | c1f7ad98a5ca7345098c0d78ceaa195c773a6c71 | |
parent | 5ed5164586e570374223e0f38ac7056bf3d03fc3 (diff) | |
parent | f4bfce20da6204567870cef57c5a27e6b68f5054 (diff) |
Merge remote-tracking branch 'upstream/2.3' into main
-rw-r--r-- | res/controllers/Denon-MC7000-scripts.js | 180 | ||||
-rw-r--r-- | res/controllers/Denon-MC7000.midi.xml | 6 | ||||
-rw-r--r-- | src/engine/controls/loopingcontrol.cpp | 23 | ||||
-rw-r--r-- | src/engine/enginemaster.cpp | 2 | ||||
-rw-r--r-- | src/engine/sync/enginesync.cpp | 5 | ||||
-rw-r--r-- | src/engine/sync/internalclock.cpp | 6 |
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); |