From f56fa545aa2b5a0dfbbb5f19a3b671c5db0deda2 Mon Sep 17 00:00:00 2001 From: holopansel Date: Wed, 20 Apr 2022 14:50:32 +0200 Subject: [PATCH 01/75] start and stop with softstart and break configurable with stop time knob, pitch play, sampler with up to 32 samplers, velocity sampler with up to 32 samplers. --- res/controllers/Denon-MC7000-scripts.js | 500 +++++++++++++++++++++--- res/controllers/Denon-MC7000.midi.xml | 82 ++-- 2 files changed, 479 insertions(+), 103 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 16d90ea6abc..1584a173390 100644 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -1,4 +1,4 @@ -/** +/* * Denon DJ MC7000 DJ controller script for Mixxx 2.3.1 * * Started in Dec. 2019 by OsZ @@ -24,8 +24,9 @@ * older Linux Kernels. You should upgrade your Kernel to minimum versions * LTS: 4.19.105 or 5.4.21, stable branch 5.5.5 or current 5.6 (2020-Feb-19). * Newer Kernels will provide native audio support for this controller. -**/ + */ +// eslint-disable-next-line no-var var MC7000 = {}; /*/////////////////////////////////// @@ -108,6 +109,8 @@ MC7000.isVinylMode = [MC7000.VinylModeOn, MC7000.VinylModeOn, MC7000.VinylModeOn // initialize the "factor" function for Spinback MC7000.factor = []; +// initialize the "factor2" function for Brake and Softstart +MC7000.factor2 = []; //Set Shift button state to false as default MC7000.shift = [false, false, false, false]; @@ -133,6 +136,12 @@ MC7000.fixedLoop = [1, 2, 4, 8, 16, 32, 64, 128]; // PAD Mode - 'Beatjump' sizes MC7000.beatJump = [1, 2, 4, 8, 16, 32, 64, 128]; +// PAD Mode - "pitch" values +MC7000.halftoneToPadMap1 = [4, 5, 6, 7, 0, 1, 2, 3]; +MC7000.halftoneToPadMap2 = [4, 5, 6, 7, 0, 1, 2, 3]; +MC7000.halftoneToPadMap3 = [4, 5, 6, 7, 0, 1, 2, 3]; +MC7000.halftoneToPadMap4 = [4, 5, 6, 7, 0, 1, 2, 3]; + // Define the MIDI signal for red LED at VU Meters MC7000.VuMeterLEDPeakValue = 0x76; @@ -141,6 +150,90 @@ MC7000.prevVuLevel = [0, 0, 0, 0]; MC7000.prevJogLED = [0, 0, 0, 0]; MC7000.prevPadLED = [0, 0, 0, 0]; +// Quantity of Samplers used in mixxx possible values 16 and 32 +MC7000.SamplerQty = 32; + +// Param Buttons for Pitch Play +MC7000.paramButton = [0, 0, 0, 0]; + +/* +color codes: + +0x followed by + + +01 off +02 dark blue +03 blue +04 bright blue +05 dark green +06 dark cyan +07 dark middle blue +08 bright blue +09 middle green +0A middle light green +0B middle cyan +0C middle blue +0D bright green +0E bright middle green +0F bright light green +10 bright cyan +11 dark red +12 dark pink +13 dark purple +14 middle purple blue +15 dark yellow +16 dark white +17 dark light blue +18 middle light blue +19 dark green/yellow +1A dark light green +1B dark light cyan +1C middle light blue +1D bright green +1E bright light green +1F bright light green +20 bright light cyan +21 middle red +22 middle pink +23 middle dark pink +24 middle purple +25 dark orange +26 dark light rose +27 dark light pink/purple +28 dark purple blue +29 dark yellow +2A dark light yellow +2B dark white +2C middle light blue +2D middle green +2E middle light green +2F middle light light green +30 middle cyan +31 bright red +32 bright pink/red +33 bright pink +34 bright pink/purple +35 bright orange amber +36 bright pink/red +37 bright pink +38 bright pink/purple +39 bright orange +3A bright light orange +3B bright light rose +3C bright light pink/purple +3D bright yellow +3E bright light yellow +3F bright light light yellow +40 bright white +*/ + +/* +button colors not set yet +slicer loop blue +flip red +*/ + // PAD Mode Colors MC7000.padColor = { "alloff": 0x01, // switch off completely @@ -148,7 +241,7 @@ MC7000.padColor = { "hotcueon": 0x04, // blue Hot Cue active "hotcueoff": 0x02, // dark blue Hot Cue inactive // Cue Loop - "cueloopon": 0x0D, // green Cueloop colour for activated cue point + "cueloopon": 0x19, // green Cueloop colour for activated cue point "cueloopoff": 0x1A, // dark green Cueloop colour inactive // Roll "rollon": 0x20, // cyan BeatloopRoll active colour @@ -162,8 +255,15 @@ MC7000.padColor = { "slicerJumpBack": 0x31, // red Sliver backward jump // Sampler "samplerloaded": 0x38, // pink Sampler loaded colour - "samplerplay": 0x09, // green Sampler playing - "sampleroff": 0x12 // dark pink Sampler standard colour + "samplerplay": 0x09, // middle green Sampler playing + "sampleroff": 0x12, // dark pink Sampler standard colour + // Velocity Sampler + "velsamploaded": 0x24, // purple VelocitySampler loaded colour + "velsampplay": 0x0A, // light green VelocitySampler playing + "velsampoff": 0x13, // dark purple VelocitySampler standard colour + // Pitch Play + "pitchon": 0x0D, // green for Pitch Play on + "pitchoff": 0x05 // dark green for Pitch Play off }; /* DECK INITIALIZATION */ @@ -206,13 +306,16 @@ MC7000.init = function() { engine.makeConnection("[Channel3]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); engine.makeConnection("[Channel4]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); } - // Sampler Mode LEDs - for (i = 1; i <= 8; i++) { + for (i = 1; i <= MC7000.SamplerQty; i++) { engine.makeConnection("[Sampler"+i+"]", "track_loaded", MC7000.SamplerLED); engine.makeConnection("[Sampler"+i+"]", "play", MC7000.SamplerLED); } - + // Sampler and Velocity Sampler Mode LEDs + for (i = 1; i <= MC7000.SamplerQty; i++) { + engine.makeConnection("[Sampler"+i+"]", "track_loaded", MC7000.VelSampLED); + engine.makeConnection("[Sampler"+i+"]", "play", MC7000.VelSampLED); + } // send Softtakeover delayed to avoid conflicts with ControllerStatusSysex engine.beginTimer(2000, function() { // Softtakeover for Pitch Faders only @@ -230,9 +333,9 @@ MC7000.samplerLevel = function(channel, control, value) { } else { engine.setValue("[Samplers]", "show_samplers", false); } - //control the 8 sampler volumes with the one knob on the mixer - for (var i = 1; i <= 8; i++) { - engine.setValue("[Sampler"+i+"]", "pregain", script.absoluteNonLin(value, 0, 1.0, 4.0)); + //control the sampler volumes with the one knob on the mixer + for (var i = 1; i <= MC7000.SamplerQty; i++) { + engine.setValue("[Sampler"+i+"]", "volume", script.absoluteLin(value, 0, 1.0, 4.0)); } }; @@ -253,7 +356,6 @@ MC7000.padModeCue = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // change PAD color when switching to Hot Cue Mode for (var i = 1; i <= 8; i++) { if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { @@ -281,7 +383,6 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // switch off PAD illumination for (var i = 0; i < 8; i++) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); @@ -305,10 +406,9 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // switch off PAD illumination for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i, MC7000.padColor.alloff); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); } }; @@ -329,7 +429,6 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // change PAD color when switching to Roll Mode for (var i = 0; i < 8; i++) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.rolloff); @@ -353,7 +452,6 @@ MC7000.padModeSavedLoop = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // change PAD color when switching to Saved Loop Mode for (var i = 0; i < 8; i++) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; @@ -378,7 +476,6 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // change PAD color when switching to Slicer Mode for (var i = 0; i < 8; i++) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.sliceron); @@ -402,7 +499,6 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // switch off PAD illumination for (var i = 0; i < 8; i++) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); @@ -413,6 +509,7 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.padModeSampler = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; + var samplerOffset = 0; if (value === 0x00) { return; // don't respond to note off messages } @@ -426,14 +523,22 @@ MC7000.padModeSampler = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = true; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; - // change PAD color when switching to Sampler Mode for (var i = 1; i <= 8; i++) { - if (engine.getValue("[Sampler" + i + "]", "play")) { + if (MC7000.SamplerQty === 16) { + if (deckOffset >= 2) { + samplerOffset = (deckOffset -2) * 8 + i; + } else { + samplerOffset = deckOffset * 8 + i; + } + } else { + samplerOffset = deckOffset * 8 + i; + } + if (engine.getValue("[Sampler" + samplerOffset + "]", "play")) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); - } else if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 0) { + } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.sampleroff); - } else if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 1 && engine.getValue("[Sampler" + i + "]", "play") === 0) { + } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerloaded); } } @@ -443,6 +548,7 @@ MC7000.padModeSampler = function(channel, control, value, status, group) { MC7000.padModeVelSamp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; + var samplerOffset = 0; if (value === 0x00) { return; // don't respond to note off messages } @@ -456,43 +562,77 @@ MC7000.padModeVelSamp = function(channel, control, value, status, group) { MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = true; MC7000.PADModePitch[deckNumber] = false; - - // switch off PAD illumination - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); + // change PAD color when switching to Velocity Sampler Mode + for (var i = 1; i <= 8; i++) { + if (MC7000.SamplerQty === 16) { + if (deckOffset >= 2) { + samplerOffset = (deckOffset -2) * 8 + i; + } else { + samplerOffset = deckOffset * 8 + i; + } + } else { + samplerOffset = deckOffset * 8 + i; + } + if (engine.getValue("[Sampler" + samplerOffset+ "]", "play")) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); + } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 0) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampoff); + } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 1) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsamploaded); + } } }; // PAD Mode Pitch +MC7000.HotcueSelectedGroup = [0, 0, 0, 0]; MC7000.padModePitch = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } + if (deckNumber === 1) { + MC7000.halftoneToPadMap1 = [4, 5, 6, 7, 0, 1, 2, 3]; + } else if (deckNumber === 2) { + MC7000.halftoneToPadMap2 = [4, 5, 6, 7, 0, 1, 2, 3]; + } else if (deckNumber === 3) { + MC7000.halftoneToPadMap3 = [4, 5, 6, 7, 0, 1, 2, 3]; + } else if (deckNumber === 4) { + MC7000.halftoneToPadMap4 = [4, 5, 6, 7, 0, 1, 2, 3]; + } + MC7000.PADModeCue[deckNumber] = false; MC7000.PADModeCueLoop[deckNumber] = false; MC7000.PADModeFlip[deckNumber] = false; MC7000.PADModeRoll[deckNumber] = false; MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = true; + MC7000.PADModeSlicer[deckNumber] = false; MC7000.PADModeSlicerLoop[deckNumber] = false; MC7000.PADModeSampler[deckNumber] = false; MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = true; - // switch off PAD illumination - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i, MC7000.padColor.alloff); + // switch on initial PAD illumination = hotcue for pitch or if + // MC7000.HotcueSelectedGroup selected = pad mode pitchoff color + for (var i = 1; i <= 8; i++) { + if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); + } else if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); + } else { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); + } } }; + // PAD buttons MC7000.PadButtons = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; - var i, j; + var i, j, z; + var samplerOffset = 0; + var samplerOffsetJ = 0; // activate and clear Hot Cues if (MC7000.PADModeCue[deckNumber] && engine.getValue(group, "track_loaded") === 1) { @@ -513,9 +653,9 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } } else if (MC7000.PADModeCueLoop[deckNumber]) { - return; + //return; // don't do anything } else if (MC7000.PADModeFlip[deckNumber]) { - return; + //return; // don't do anything } else if (MC7000.PADModeRoll[deckNumber]) { // TODO(all): check for actual beatloop_size and apply back after a PAD Roll i = control - 0x14; @@ -561,39 +701,143 @@ MC7000.PadButtons = function(channel, control, value, status, group) { midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.sliceron); } } else if (MC7000.PADModeSlicerLoop[deckNumber]) { - return; + //return; // don't do anything } else if (MC7000.PADModeSampler[deckNumber]) { for (i = 1; i <= 8; i++) { + if (MC7000.SamplerQty === 16) { + if (deckOffset >= 2) { + deckOffset = deckOffset - 2; + } + } + samplerOffset = deckOffset * 8 + i; if (control === 0x14 + i - 1 && value >= 0x01) { - if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 0) { - engine.setValue("[Sampler" + i + "]", "LoadSelectedTrack", 1); - } else if (engine.getValue("[Sampler" + i + "]", "track_loaded") === 1) { + if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { + engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); + } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { - // stop playing all other samplers ... - for (j = 1; j <=8; j++) { - engine.setValue("[Sampler" + j + "]", "cue_gotoandstop", 1); + // stop playing all other samplers on this deck + for (j = 1; j <= 8; j++) { + samplerOffsetJ = deckOffset * 8 + j; + if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it + engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + } } } // ... before the actual sampler to play gets started - engine.setValue("[Sampler" + i + "]", "cue_gotoandplay", 1); + engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); + engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); } - } else if (control === 0x1C + i - 1 && value >= 0x01) { - if (engine.getValue("[Sampler" + i + "]", "play") === 1) { - engine.setValue("[Sampler" + i + "]", "cue_gotoandstop", 1); + } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler + if (MC7000.SamplerQty === 16) { + if ((deckNumber - 1) >= 2) { + deckOffset = deckOffset + 2; + } + } + if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { + engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandstop", 1); midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.samplerloaded); } else { - engine.setValue("[Sampler" + i + "]", "eject", 1); + engine.setValue("[Sampler" + samplerOffset + "]", "eject", 1); midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.sampleroff); - engine.setValue("[Sampler" + i + "]", "eject", 0); + engine.setValue("[Sampler" + samplerOffset + "]", "eject", 0); } } } - } else if (MC7000.PADModeVelSamp[deckNumber]) { - return; - } else if (MC7000.PADModePitch[deckNumber]) { - return; - } -}; + } else if (MC7000.PADModeVelSamp[deckNumber]) { // reset pregain on stop required? + for (i = 1; i <= 8; i++) { + if (MC7000.SamplerQty === 16) { + if (deckOffset >= 2) { + deckOffset = deckOffset - 2; + } + } + samplerOffset = deckOffset * 8 + i; + if (control === 0x14 + i - 1 && value >= 0x01) { + if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { // if sampler is not loaded, load sampler and set color to loaded + engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); + } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { + if (MC7000.prevSamplerStop) { + // stop playing all other samplers on this deck + for (j = 1; j <= 8; j++) { + samplerOffsetJ = deckOffset * 8 + j; + if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it + engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + } + } + } + // ... before the actual sampler to play gets started + engine.setValue("[Sampler" + samplerOffset + "]", "pregain", script.absoluteNonLin(value, 0, 1.0, 4.0)); + engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); + } + } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler + if (MC7000.SamplerQty === 16) { + if ((deckNumber - 1) >= 2) { + deckOffset = deckOffset + 2; + } + } + if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { + engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandstop", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.velsamploaded); + } else { + engine.setValue("[Sampler" + samplerOffset + "]", "eject", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.velsampoff); + engine.setValue("[Sampler" + samplerOffset + "]", "eject", 0); + } + } + } + } else if (MC7000.PADModePitch[deckNumber]) { // TODO TODO play and cue dependency to play and cue button + if (MC7000.PADModePitch[deckNumber] && engine.getValue(group, "track_loaded") === 1) { + for (i = 1; i <= 8; i++) { + if (value === 0x7F && control === 0x14 + i - 1 && engine.getValue(group, "hotcue_" + i + "_enabled") === 0 && MC7000.HotcueSelectedGroup[deckOffset] === 0) { //hotcue select if none available + engine.setValue(group, "hotcue_" + i + "_activate", true); // set hotcue if not set before + MC7000.HotcueSelectedGroup[deckOffset] = i; + for (z = 1; z <= 8; z++) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // if hotcue is selected switch to pitch off color + } + } else if (value === 0x7F && control === 0x14 + i - 1 && engine.getValue(group, "hotcue_" + i + "_enabled") === 1 && MC7000.HotcueSelectedGroup[deckOffset] === 0) { // hotcue select if available + MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch + for (z = 1; z <= 8; z++) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // if hotcue is selected switch to pitch off color + } + } else if (value === 0x7F && control === 0x14 + i - 1 && MC7000.HotcueSelectedGroup[deckOffset] > 0) { // hotcue selected and button pressed // TODO: play if play, stop if cue + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop + for (z = 1; z <= 8; z++) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // switch to pitch off color + } + if (deckNumber === 1) { + engine.setValue(group, "pitch", MC7000.halftoneToPadMap1[i-1]); + } else if (deckNumber === 2) { + engine.setValue(group, "pitch", MC7000.halftoneToPadMap2[i-1]); + } else if (deckNumber === 3) { + engine.setValue(group, "pitch", MC7000.halftoneToPadMap3[i-1]); + } else if (deckNumber === 4) { + engine.setValue(group, "pitch", MC7000.halftoneToPadMap3[i-1]); + } + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color + } else if (control === 0x14 + i - 1 && value === 0x00) { // button release change color and stop play + // engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop //TODO if for setting continue to play or stop on button release + // midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); // switch to pitch off color + 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) { //shifted buttons deselect hotcue for pitch + engine.setValue(group, "pitch", 0); + MC7000.HotcueSelectedGroup[deckOffset] = 0; + for (z = 1; z <= 8; z++) { + if (engine.getValue(group, "hotcue_" + z + "_enabled", true)) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.hotcueon); + } else { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.hotcueoff); + } + } + } // end else if + } // end for + } //end pad mode if + } //end pad mode pitch +}; //end pad buttons // Shift Button MC7000.shiftButton = function(channel, control, value, status, group) { @@ -834,10 +1078,37 @@ MC7000.crossfaderAssign = function(channel, control, value, status, group) { // Assign Spinback length to STOP TIME knob MC7000.stopTime = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - // "factor" for engine.brake() + // "factor" for engine.brake() and engine.softStart() // this formula produces factors between 31 (min STOP TIME for ca 7 sec back // in track) and 1 (max STOP TIME for ca 18.0 sec back in track) MC7000.factor[deckNumber] = (1.1 - (value / 127)) * 30 - 2; + MC7000.factor2[deckNumber] = (127.69 - value); +}; +MC7000.lastpress = 0; +MC7000.play = function(channel, control, value, status, group) { + if (value === 0x00) { + return; // don't respond to note off messages + } + var deckNumber = script.deckFromGroup(group); + // set a variable to toggle between play and pause, based on current play status + var playToggle = 1 - engine.getValue(group, "play_indicator"); + if (MC7000.factor[deckNumber] === 31) { // factor 31 means stop time knob is at zero position + engine.setValue(group, "play", playToggle); + MC7000.lastpress = 0; + } else { + if (!playToggle) { + if (!MC7000.lastpress) { + engine.brake(deckNumber, true, MC7000.factor2[deckNumber]); + MC7000.lastpress = 1; + } else { + engine.softStart(deckNumber, true, MC7000.factor2[deckNumber]); + MC7000.lastpress = 0; + } + } else { + engine.softStart(deckNumber, true, MC7000.factor2[deckNumber]); + MC7000.lastpress = 0; + } + } }; // Use SHIFT + CENSOR button as Spinback with STOP TIME adjusted length @@ -883,6 +1154,55 @@ MC7000.censor = function(channel, control, value, status, group) { } }; +// Param Button for Pitch Play to increase or decrease pitch, Star rating otherwise +MC7000.StarsDown = function(channel, control, value, status, group) { + var deckNumber = script.deckFromGroup(group); + //var deckOffset = deckNumber - 1; + if (value === 0x00) { + //return; // don't respond to note off messages + } else { + if (MC7000.PADModePitch[deckNumber]) { + for (var i = 1; i <= 8; i++) { + if (deckNumber === 1) { + MC7000.halftoneToPadMap1[i-1] = MC7000.halftoneToPadMap1[i-1] - 8; // pitch down + } else if (deckNumber === 2) { + MC7000.halftoneToPadMap2[i-1] = MC7000.halftoneToPadMap2[i-1] - 8; // pitch down + } else if (deckNumber === 3) { + MC7000.halftoneToPadMap3[i-1] = MC7000.halftoneToPadMap3[i-1] - 8; // pitch down + } else if (deckNumber === 4) { + MC7000.halftoneToPadMap4[i-1] = MC7000.halftoneToPadMap4[i-1] - 8; // pitch down + } + } + } else { + engine.setValue(group, "stars_down", true); // stars down + } + } +}; + +MC7000.StarsUp = function(channel, control, value, status, group) { + var deckNumber = script.deckFromGroup(group); + //var deckOffset = deckNumber - 1; + if (value === 0x00) { + //return; // don't respond to note off messages + } else { + if (MC7000.PADModePitch[deckNumber]) { + for (var i = 1; i <= 8; i++) { + if (deckNumber === 1) { + MC7000.halftoneToPadMap1[i-1] = MC7000.halftoneToPadMap1[i-1] + 8; // pitch up + } else if (deckNumber === 2) { + MC7000.halftoneToPadMap2[i-1] = MC7000.halftoneToPadMap2[i-1] + 8; // pitch up + } else if (deckNumber === 3) { + MC7000.halftoneToPadMap3[i-1] = MC7000.halftoneToPadMap3[i-1] + 8; // pitch up + } else if (deckNumber === 4) { + MC7000.halftoneToPadMap4[i-1] = MC7000.halftoneToPadMap4[i-1] + 8; // pitch up + } + } + } else { + engine.setValue(group, "stars_up", true); // stars up + } + } +}; + // Set Crossfader Curve MC7000.crossFaderCurve = function(control, value) { script.crossfaderCurve(value); @@ -952,7 +1272,6 @@ MC7000.TrackPositionLEDs = function(value, group) { var activeJogLED = MC7000.isVinylMode[deckOffset] ? Math.round(jogLEDPosition * jogLEDNumber) % jogLEDNumber : Math.round(value * jogLEDNumber); // count the beats (1 to 8) after the CUE point var beatCountLED = (Math.floor((playPosition - cuePosition) * beatLength) % 8); //calculate PAD LED position - // TODO(all): check for playposition < (trackduration - warning length) for sending position signals // check if a Jog LED has changed and if so then send the signal to the next Jog LED if (MC7000.prevJogLED[deckOffset] !== activeJogLED) { @@ -960,7 +1279,6 @@ MC7000.TrackPositionLEDs = function(value, group) { MC7000.prevJogLED[deckOffset] = activeJogLED; } // TODO(all): else blink the platter LEDs - // check if Slicer mode is active and illuminate PAD LEDs counting with the beat while playing if (!MC7000.experimental) { return; @@ -1011,14 +1329,24 @@ MC7000.HotCueLED = function(value, group) { MC7000.SamplerLED = function() { for (var j = 1; j <= 4; j++) { for (var i = 1; i <= 8; i++) { + var sampNo = 0; if (MC7000.PADModeSampler[j]) { - if (engine.getValue("[Sampler"+i+"]", "track_loaded") === 1) { - if (engine.getValue("[Sampler"+i+"]", "play") === 0) { + if (MC7000.SamplerQty === 16) { + if (j >= 3) { + sampNo = (j - 3) * 8 + i; + } else { + sampNo = (j - 1) * 8 + i; + } + } else if (MC7000.SamplerQty === 32) { + sampNo = (j - 1) * 8 + i; + } + if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { + if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.samplerloaded); } else { midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.samplerplay); } - } else if (engine.getValue("[Sampler"+i+"]", "track_loaded") === 0) { + } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.sampleroff); } } @@ -1026,14 +1354,62 @@ MC7000.SamplerLED = function() { } }; +// Velocity Sampler LED +MC7000.VelSampLED = function() { + for (var j = 1; j <= 4; j++) { + for (var i = 1; i <= 8; i++) { + var sampNo = 0; + if (MC7000.PADModeVelSamp[j]) { + if (MC7000.SamplerQty === 16) { + if (j >= 3) { + sampNo = (j - 3) * 8 + i; + } else { + sampNo = (j - 1) * 8 + i; + } + } else { + sampNo = (j - 1) * 8 + i; + } + if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { + if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { + midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsamploaded); + } else { + midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsampplay); + } + } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { + midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsampoff); + } + } + } + } +}; + +// initial HotCue LED when loading a track with already existing hotcues for pitch +MC7000.PitchLED = function(value, group) { + var deckNumber = script.deckFromGroup(group); + var deckOffset = deckNumber - 1; + if (MC7000.PADModePitch[deckNumber]) { + for (var i = 1; i <= 8; i++) { + if (value === 1) { + if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); + } + } else { + if (engine.getValue(group, "hotcue_"+i+"_enabled") === 0) { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); + } + } + } + } +}; + /* CONTROLLER SHUTDOWN */ MC7000.shutdown = function() { - + var i; // Need to switch off LEDs one by one, // otherwise the controller cannot handle the signal traffic // Switch off Transport section LEDs - for (var i = 0; i <= 3; i++) { + for (i = 0; i <= 3; i++) { midi.sendShortMsg(0x90 + i, 0x00, 0x01); midi.sendShortMsg(0x90 + i, 0x01, 0x01); midi.sendShortMsg(0x90 + i, 0x02, 0x01); diff --git a/res/controllers/Denon-MC7000.midi.xml b/res/controllers/Denon-MC7000.midi.xml index fa66ed534fe..9e2fe44617c 100644 --- a/res/controllers/Denon-MC7000.midi.xml +++ b/res/controllers/Denon-MC7000.midi.xml @@ -2,7 +2,7 @@ Denon MC7000 - OsZ + OsZ/JL 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. https://mixxx.discourse.group/t/denon-mc7000-mapping/18235 https://github.com/mixxxdj/mixxx/wiki/Denon-MC7000 @@ -1314,42 +1314,42 @@ [Channel1] - play + MC7000.play Play Ch1 0x90 0x00 - + [Channel2] - play + MC7000.play Play Ch2 0x91 0x00 - + [Channel3] - play + MC7000.play Play Ch3 0x92 0x00 - + [Channel4] - play + MC7000.play Play Ch4 0x93 0x00 - + @@ -1688,7 +1688,7 @@ loop_halve X1/2 Ch1 0x94 - 0x34 + 0x38 @@ -1698,7 +1698,7 @@ loop_halve X1/2 Ch2 0x95 - 0x34 + 0x38 @@ -1708,7 +1708,7 @@ loop_halve X1/2 Ch3 0x96 - 0x34 + 0x38 @@ -1718,7 +1718,7 @@ loop_halve X1/2 Ch4 0x97 - 0x34 + 0x38 @@ -1728,7 +1728,7 @@ loop_double X2 Ch1 0x94 - 0x35 + 0x39 @@ -1738,7 +1738,7 @@ loop_double X2 Ch2 0x95 - 0x35 + 0x39 @@ -1748,7 +1748,7 @@ loop_double X2 Ch3 0x96 - 0x35 + 0x39 @@ -1758,7 +1758,7 @@ loop_double X2 Ch4 0x97 - 0x35 + 0x39 @@ -1768,7 +1768,7 @@ loop_in Loop in Ch1 0x94 - 0x38 + 0x34 @@ -1778,7 +1778,7 @@ loop_in Loop in Ch2 0x95 - 0x38 + 0x34 @@ -1788,7 +1788,7 @@ loop_in Loop in Ch3 0x96 - 0x38 + 0x34 @@ -1798,7 +1798,7 @@ loop_in Loop in Ch4 0x97 - 0x38 + 0x34 @@ -1808,7 +1808,7 @@ loop_out Loop out Ch1 0x94 - 0x39 + 0x35 @@ -1818,7 +1818,7 @@ loop_out Loop out Ch2 0x95 - 0x39 + 0x35 @@ -1828,7 +1828,7 @@ loop_out Loop out Ch3 0x96 - 0x39 + 0x35 @@ -1838,7 +1838,7 @@ loop_out Loop out Ch4 0x97 - 0x39 + 0x35 @@ -1886,22 +1886,22 @@ [Channel1] - stars_down + MC7000.StarsDown 0x94 0x28 - + [Channel1] - stars_up + MC7000.StarsUp 0x94 0x29 - + @@ -1926,22 +1926,22 @@ [Channel2] - stars_down + MC7000.StarsDown 0x95 0x28 - + [Channel2] - stars_up + MC7000.StarsUp 0x95 0x29 - + @@ -1966,22 +1966,22 @@ [Channel3] - stars_down + MC7000.StarsDown 0x96 0x28 - + [Channel3] - stars_up + MC7000.StarsUp 0x96 0x29 - + @@ -2006,22 +2006,22 @@ [Channel4] - stars_down + MC7000.StarsDown 0x97 0x28 - + [Channel4] - stars_up + MC7000.StarsUp 0x97 0x29 - + From 3377299acf786da9adeff4103d59f16ddbf7d7c0 Mon Sep 17 00:00:00 2001 From: holopansel Date: Fri, 22 Apr 2022 13:57:57 +0200 Subject: [PATCH 02/75] removed comment due to code style errors --- res/controllers/Denon-MC7000-scripts.js | 4 ++-- res/controllers/Denon-MC7000.midi.xml | 32 ++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 1584a173390..a7df62a3499 100644 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -26,7 +26,7 @@ * Newer Kernels will provide native audio support for this controller. */ -// eslint-disable-next-line no-var + var MC7000 = {}; /*/////////////////////////////////// @@ -600,7 +600,7 @@ MC7000.padModePitch = function(channel, control, value, status, group) { } else if (deckNumber === 4) { MC7000.halftoneToPadMap4 = [4, 5, 6, 7, 0, 1, 2, 3]; } - + MC7000.PADModeCue[deckNumber] = false; MC7000.PADModeCueLoop[deckNumber] = false; MC7000.PADModeFlip[deckNumber] = false; diff --git a/res/controllers/Denon-MC7000.midi.xml b/res/controllers/Denon-MC7000.midi.xml index 9e2fe44617c..bb2adcdce86 100644 --- a/res/controllers/Denon-MC7000.midi.xml +++ b/res/controllers/Denon-MC7000.midi.xml @@ -1688,7 +1688,7 @@ loop_halve X1/2 Ch1 0x94 - 0x38 + 0x34 @@ -1698,7 +1698,7 @@ loop_halve X1/2 Ch2 0x95 - 0x38 + 0x34 @@ -1708,7 +1708,7 @@ loop_halve X1/2 Ch3 0x96 - 0x38 + 0x34 @@ -1718,7 +1718,7 @@ loop_halve X1/2 Ch4 0x97 - 0x38 + 0x34 @@ -1728,7 +1728,7 @@ loop_double X2 Ch1 0x94 - 0x39 + 0x35 @@ -1738,7 +1738,7 @@ loop_double X2 Ch2 0x95 - 0x39 + 0x35 @@ -1748,7 +1748,7 @@ loop_double X2 Ch3 0x96 - 0x39 + 0x35 @@ -1758,7 +1758,7 @@ loop_double X2 Ch4 0x97 - 0x39 + 0x35 @@ -1768,7 +1768,7 @@ loop_in Loop in Ch1 0x94 - 0x34 + 0x38 @@ -1778,7 +1778,7 @@ loop_in Loop in Ch2 0x95 - 0x34 + 0x38 @@ -1788,7 +1788,7 @@ loop_in Loop in Ch3 0x96 - 0x34 + 0x38 @@ -1798,7 +1798,7 @@ loop_in Loop in Ch4 0x97 - 0x34 + 0x38 @@ -1808,7 +1808,7 @@ loop_out Loop out Ch1 0x94 - 0x35 + 0x39 @@ -1818,7 +1818,7 @@ loop_out Loop out Ch2 0x95 - 0x35 + 0x39 @@ -1828,7 +1828,7 @@ loop_out Loop out Ch3 0x96 - 0x35 + 0x39 @@ -1838,7 +1838,7 @@ loop_out Loop out Ch4 0x97 - 0x35 + 0x39 From b430915107e8e3f72fa4883317ebc59f3b16cb08 Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Jun 2022 12:45:54 +0200 Subject: [PATCH 03/75] update with suggestions from Swiftb0y --- res/controllers/Denon-MC7000-scripts.js | 172 ++++++++++-------------- res/controllers/Denon-MC7000.midi.xml | 2 +- 2 files changed, 70 insertions(+), 104 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 61fb2cc322c..fc0e3ca4414 100644 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -137,10 +137,7 @@ MC7000.fixedLoop = [1, 2, 4, 8, 16, 32, 64, 128]; MC7000.beatJump = [1, 2, 4, 8, 16, 32, 64, 128]; // PAD Mode - "pitch" values -MC7000.halftoneToPadMap1 = [4, 5, 6, 7, 0, 1, 2, 3]; -MC7000.halftoneToPadMap2 = [4, 5, 6, 7, 0, 1, 2, 3]; -MC7000.halftoneToPadMap3 = [4, 5, 6, 7, 0, 1, 2, 3]; -MC7000.halftoneToPadMap4 = [4, 5, 6, 7, 0, 1, 2, 3]; +MC7000.halftoneToPadMap = [[4, 5, 6, 7, 0, 1, 2, 3], [4, 5, 6, 7, 0, 1, 2, 3], [4, 5, 6, 7, 0, 1, 2, 3], [4, 5, 6, 7, 0, 1, 2, 3]]; // Define the MIDI signal for red LED at VU Meters MC7000.VuMeterLEDPeakValue = 0x76; @@ -316,6 +313,13 @@ MC7000.init = function() { engine.makeConnection("[Sampler"+i+"]", "track_loaded", MC7000.VelSampLED); engine.makeConnection("[Sampler"+i+"]", "play", MC7000.VelSampLED); } + //Pitch LEDs + for (i = 1; i <= 8; i++) { + engine.makeConnection("[Channel1]", "hotcue_"+i+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel2]", "hotcue_"+i+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel3]", "hotcue_"+i+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel4]", "hotcue_"+i+"_enabled", MC7000.PitchLED); + } // send Softtakeover delayed to avoid conflicts with ControllerStatusSysex engine.beginTimer(2000, function() { // Softtakeover for Pitch Faders only @@ -384,9 +388,7 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); - } + MC7000.sendColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Flip @@ -407,9 +409,7 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); - } + MC7000.sendColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Roll @@ -430,9 +430,7 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Roll Mode - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.rolloff); - } + MC7000.sendColor(deckOffset, MC7000.padColor.rolloff); }; // PAD Mode Saved Loop @@ -477,9 +475,7 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Slicer Mode - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.sliceron); - } + MC7000.sendColor(deckOffset, MC7000.padColor.sliceron); }; // PAD Mode Slicer Loop @@ -500,9 +496,7 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - for (var i = 0; i < 8; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.alloff); - } + MC7000.sendColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Sampler @@ -524,16 +518,10 @@ MC7000.padModeSampler = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Sampler Mode + var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; + var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; for (var i = 1; i <= 8; i++) { - if (MC7000.SamplerQty === 16) { - if (deckOffset >= 2) { - samplerOffset = (deckOffset -2) * 8 + i; - } else { - samplerOffset = deckOffset * 8 + i; - } - } else { - samplerOffset = deckOffset * 8 + i; - } + samplerOffset = samplerUnitOffset + i; if (engine.getValue("[Sampler" + samplerOffset + "]", "play")) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { @@ -563,16 +551,10 @@ MC7000.padModeVelSamp = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = true; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Velocity Sampler Mode + var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; + var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; for (var i = 1; i <= 8; i++) { - if (MC7000.SamplerQty === 16) { - if (deckOffset >= 2) { - samplerOffset = (deckOffset -2) * 8 + i; - } else { - samplerOffset = deckOffset * 8 + i; - } - } else { - samplerOffset = deckOffset * 8 + i; - } + samplerOffset = samplerUnitOffset + i; if (engine.getValue("[Sampler" + samplerOffset+ "]", "play")) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 0) { @@ -591,15 +573,7 @@ MC7000.padModePitch = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - if (deckNumber === 1) { - MC7000.halftoneToPadMap1 = [4, 5, 6, 7, 0, 1, 2, 3]; - } else if (deckNumber === 2) { - MC7000.halftoneToPadMap2 = [4, 5, 6, 7, 0, 1, 2, 3]; - } else if (deckNumber === 3) { - MC7000.halftoneToPadMap3 = [4, 5, 6, 7, 0, 1, 2, 3]; - } else if (deckNumber === 4) { - MC7000.halftoneToPadMap4 = [4, 5, 6, 7, 0, 1, 2, 3]; - } + MC7000.halftoneToPadMap[deckNumber-1] = [4, 5, 6, 7, 0, 1, 2, 3]; MC7000.PADModeCue[deckNumber] = false; MC7000.PADModeCueLoop[deckNumber] = false; @@ -631,8 +605,6 @@ MC7000.PadButtons = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; var i, j, z; - var samplerOffset = 0; - var samplerOffsetJ = 0; // The following modes are currently unhandled and could be // added as if-branches in the future: @@ -675,7 +647,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } i = control - 0x14; engine.setValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_toggle", true); - for (j =0; j < 8; j++) { + for (j = 0; j < 8; j++) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[j] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; midi.sendShortMsg(0x94 + deckOffset, 0x14 + j, activeLED); } @@ -704,6 +676,8 @@ MC7000.PadButtons = function(channel, control, value, status, group) { midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.sliceron); } } else if (MC7000.PADModeSampler[deckNumber]) { + var samplerOffset = 0; + var samplerOffsetJ = 0; for (i = 1; i <= 8; i++) { if (MC7000.SamplerQty === 16) { if (deckOffset >= 2) { @@ -744,7 +718,9 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } } - } else if (MC7000.PADModeVelSamp[deckNumber]) { // reset pregain on stop required? + } else if (MC7000.PADModeVelSamp[deckNumber]) { + samplerOffset = 0; + samplerOffsetJ = 0; for (i = 1; i <= 8; i++) { if (MC7000.SamplerQty === 16) { if (deckOffset >= 2) { @@ -770,6 +746,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); } } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler + engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); if (MC7000.SamplerQty === 16) { if ((deckNumber - 1) >= 2) { deckOffset = deckOffset + 2; @@ -786,36 +763,29 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } } else if (MC7000.PADModePitch[deckNumber]) { // TODO TODO play and cue dependency to play and cue button - if (MC7000.PADModePitch[deckNumber] && engine.getValue(group, "track_loaded") === 1) { + if (engine.getValue(group, "track_loaded") === 1) { for (i = 1; i <= 8; i++) { - if (value === 0x7F && control === 0x14 + i - 1 && engine.getValue(group, "hotcue_" + i + "_enabled") === 0 && MC7000.HotcueSelectedGroup[deckOffset] === 0) { //hotcue select if none available - engine.setValue(group, "hotcue_" + i + "_activate", true); // set hotcue if not set before - MC7000.HotcueSelectedGroup[deckOffset] = i; - for (z = 1; z <= 8; z++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // if hotcue is selected switch to pitch off color - } - } else if (value === 0x7F && control === 0x14 + i - 1 && engine.getValue(group, "hotcue_" + i + "_enabled") === 1 && MC7000.HotcueSelectedGroup[deckOffset] === 0) { // hotcue select if available - MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch - for (z = 1; z <= 8; z++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // if hotcue is selected switch to pitch off color - } - } else if (value === 0x7F && control === 0x14 + i - 1 && MC7000.HotcueSelectedGroup[deckOffset] > 0) { // hotcue selected and button pressed // TODO: play if play, stop if cue - engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop - for (z = 1; z <= 8; z++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.pitchoff); // switch to pitch off color - } - if (deckNumber === 1) { - engine.setValue(group, "pitch", MC7000.halftoneToPadMap1[i-1]); - } else if (deckNumber === 2) { - engine.setValue(group, "pitch", MC7000.halftoneToPadMap2[i-1]); - } else if (deckNumber === 3) { - engine.setValue(group, "pitch", MC7000.halftoneToPadMap3[i-1]); - } else if (deckNumber === 4) { - engine.setValue(group, "pitch", MC7000.halftoneToPadMap3[i-1]); + // intermediate variables + var ButtonPressed = (value === 0x7F), ButtonReleased = (value === 0x00), ControlNumber1 = (control === 0x14 + i -1), ControlNumber2 = (control === 0x1C + i -1); + var HotcueOn = engine.getValue(group, "hotcue_" + i + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckOffset]; + if (ButtonPressed && ControlNumber1) { + if (!HotcueSelectedOnDeck) { + if (!HotcueOn) { //hotcue select if none available + engine.setValue(group, "hotcue_" + i + "_activate", true); // set hotcue if not set before + MC7000.HotcueSelectedGroup[deckOffset] = i; + MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); + } else { // hotcue select if available + MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch + MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); + } + } else { // hotcue selected and button pressed // TODO: play if play, stop if cue + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop + MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); + engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckNumber-1][i-1]); + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color } - engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color - } else if (control === 0x14 + i - 1 && value === 0x00) { // button release change color and stop play + } else if (ButtonReleased && ControlNumber1) { // button release change color and stop play // engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop //TODO if for setting continue to play or stop on button release // midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); // switch to pitch off color if (engine.getValue(group, "slip_enabled")) { @@ -824,7 +794,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue(group, "slip_enabled", true); }, true); } - } else if (control === 0x1C + i - 1 && value === 0x7F) { //shifted buttons deselect hotcue for pitch + } else if (ButtonPressed && ControlNumber2) { //shifted buttons deselect hotcue for pitch engine.setValue(group, "pitch", 0); MC7000.HotcueSelectedGroup[deckOffset] = 0; for (z = 1; z <= 8; z++) { @@ -840,6 +810,13 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } //end pad mode pitch }; //end pad buttons + +MC7000.sendColor = function(sendColorDeckOffset, ColorCode) { + for (var z = 1; z <= 8; z++) { + midi.sendShortMsg(0x94 + sendColorDeckOffset, 0x14 + z - 1, ColorCode); // switch 8 buttons to selected color + } +}; + // Shift Button MC7000.shiftButton = function(channel, control, value, status, group) { var deckOffset = script.deckFromGroup(group) - 1; @@ -1164,15 +1141,7 @@ MC7000.StarsDown = function(channel, control, value, status, group) { } else { if (MC7000.PADModePitch[deckNumber]) { for (var i = 1; i <= 8; i++) { - if (deckNumber === 1) { - MC7000.halftoneToPadMap1[i-1] = MC7000.halftoneToPadMap1[i-1] - 8; // pitch down - } else if (deckNumber === 2) { - MC7000.halftoneToPadMap2[i-1] = MC7000.halftoneToPadMap2[i-1] - 8; // pitch down - } else if (deckNumber === 3) { - MC7000.halftoneToPadMap3[i-1] = MC7000.halftoneToPadMap3[i-1] - 8; // pitch down - } else if (deckNumber === 4) { - MC7000.halftoneToPadMap4[i-1] = MC7000.halftoneToPadMap4[i-1] - 8; // pitch down - } + MC7000.halftoneToPadMap[deckNumber-1][i-1] = MC7000.halftoneToPadMap[deckNumber-1][i-1] - 8; // pitch down } } else { engine.setValue(group, "stars_down", true); // stars down @@ -1188,15 +1157,7 @@ MC7000.StarsUp = function(channel, control, value, status, group) { } else { if (MC7000.PADModePitch[deckNumber]) { for (var i = 1; i <= 8; i++) { - if (deckNumber === 1) { - MC7000.halftoneToPadMap1[i-1] = MC7000.halftoneToPadMap1[i-1] + 8; // pitch up - } else if (deckNumber === 2) { - MC7000.halftoneToPadMap2[i-1] = MC7000.halftoneToPadMap2[i-1] + 8; // pitch up - } else if (deckNumber === 3) { - MC7000.halftoneToPadMap3[i-1] = MC7000.halftoneToPadMap3[i-1] + 8; // pitch up - } else if (deckNumber === 4) { - MC7000.halftoneToPadMap4[i-1] = MC7000.halftoneToPadMap4[i-1] + 8; // pitch up - } + MC7000.halftoneToPadMap[deckNumber-1][i-1] = MC7000.halftoneToPadMap[deckNumber-1][i-1] + 8; // pitch up } } else { engine.setValue(group, "stars_up", true); // stars up @@ -1373,6 +1334,7 @@ MC7000.VelSampLED = function() { if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsamploaded); + engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); } else { midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsampplay); } @@ -1384,25 +1346,29 @@ MC7000.VelSampLED = function() { } }; -// initial HotCue LED when loading a track with already existing hotcues for pitch +// Pitch LED when loading a track with already existing hotcues for pitch MC7000.PitchLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; if (MC7000.PADModePitch[deckNumber]) { for (var i = 1; i <= 8; i++) { - if (value === 1) { - if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { + if (engine.getValue("[Channel"+deckNumber+"]", "play") === 0) { // stopped + if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { // hotcue selected + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); + } else if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); - } - } else { - if (engine.getValue(group, "hotcue_"+i+"_enabled") === 0) { + } else { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); } + } else { + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); } } } }; + + /* CONTROLLER SHUTDOWN */ MC7000.shutdown = function() { var i; diff --git a/res/controllers/Denon-MC7000.midi.xml b/res/controllers/Denon-MC7000.midi.xml index bb2adcdce86..7fdcb571ff4 100644 --- a/res/controllers/Denon-MC7000.midi.xml +++ b/res/controllers/Denon-MC7000.midi.xml @@ -2,7 +2,7 @@ Denon MC7000 - OsZ/JL + OsZ, JL 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. https://mixxx.discourse.group/t/denon-mc7000-mapping/18235 https://github.com/mixxxdj/mixxx/wiki/Denon-MC7000 From 58e8978fca7f5df459cc7f23da3c1a34d887b24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 23 Oct 2022 13:07:39 +0200 Subject: [PATCH 04/75] Allow file tags with tuning information written by Rapid Evolution --- src/track/keyutils.cpp | 13 +++++++++++-- src/track/keyutils.h | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/track/keyutils.cpp b/src/track/keyutils.cpp index 595ed75c18e..31a27ab75c5 100644 --- a/src/track/keyutils.cpp +++ b/src/track/keyutils.cpp @@ -247,8 +247,17 @@ QString KeyUtils::getGlobalKeyText(const Keys& keys, KeyNotation notation) { } // static -ChromaticKey KeyUtils::guessKeyFromText(const QString& text) { - QString trimmed = text.trimmed(); +ChromaticKey KeyUtils::guessKeyFromText(QString text) { + // Remove Shift (Tuning) Information used by Rapid Evolution like: "A#m +50"; + int shiftStart = text.indexOf('+'); + if (shiftStart < 0) { + shiftStart = text.indexOf('-'); + } + if (shiftStart >= 0) { + text = text.left(shiftStart); + } + const QString trimmed = text.trimmed(); + if (trimmed.isEmpty()) { return mixxx::track::io::key::INVALID; } diff --git a/src/track/keyutils.h b/src/track/keyutils.h index 5ac8d19dc0a..7e5b8751d3c 100644 --- a/src/track/keyutils.h +++ b/src/track/keyutils.h @@ -76,7 +76,7 @@ class KeyUtils { static QList getCompatibleKeys( mixxx::track::io::key::ChromaticKey key); - static mixxx::track::io::key::ChromaticKey guessKeyFromText(const QString& text); + static mixxx::track::io::key::ChromaticKey guessKeyFromText(QString text); static mixxx::track::io::key::ChromaticKey calculateGlobalKey( const KeyChangeList& key_changes, int iTotalSamples, int iSampleRate); From acbc16b8fa90e08ea813620a96127bbae92be953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 23 Oct 2022 13:08:59 +0200 Subject: [PATCH 05/75] Improve readability --- src/track/track.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/track/track.cpp b/src/track/track.cpp index f4acaaa54ff..68c30e805e1 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -151,9 +151,9 @@ void Track::importMetadata( // overwriting with an inconsistent value. The bpm must always be // set together with the beat grid and the key text must be parsed // and validated. - const auto importedBpm = importedMetadata.getTrackInfo().getBpm(); + const mixxx::Bpm importedBpm = importedMetadata.getTrackInfo().getBpm(); importedMetadata.refTrackInfo().setBpm(getBpmWhileLocked()); - const auto importedKeyText = importedMetadata.getTrackInfo().getKey(); + const QString importedKeyText = importedMetadata.getTrackInfo().getKey(); importedMetadata.refTrackInfo().setKey(m_record.getMetadata().getTrackInfo().getKey()); bool modified = false; From 157af7d087a93e32e2eb7e3aea2178c2c371a030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 23 Oct 2022 13:10:36 +0200 Subject: [PATCH 06/75] Allow Lancelot notation with a leading zero --- src/track/keyutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/track/keyutils.cpp b/src/track/keyutils.cpp index 31a27ab75c5..1e293230596 100644 --- a/src/track/keyutils.cpp +++ b/src/track/keyutils.cpp @@ -17,7 +17,7 @@ using mixxx::track::io::key::ChromaticKey_IsValid; static const QString s_openKeyPattern("^\\s*(1[0-2]|[1-9])([dm])\\s*$"); // Lancelot notation, the numbers 1-12 followed by a (minor) or b (major). -static const QString s_lancelotKeyPattern("^\\s*(1[0-2]|[1-9])([ab])\\s*$"); +static const QString s_lancelotKeyPattern("^\\s*(1[0-2]|0?[1-9])([ab])\\s*$"); // a-g followed by any number of sharps or flats, optionally followed by // a scale spec (m = minor, min, maj) From 87157a3d0dedd603661f311de32b6a6985440b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 23 Oct 2022 13:09:24 +0200 Subject: [PATCH 07/75] Add Tests from RapidEvolution --- src/test/keyutilstest.cpp | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/test/keyutilstest.cpp b/src/test/keyutilstest.cpp index d8fb1481073..02adce28a25 100644 --- a/src/test/keyutilstest.cpp +++ b/src/test/keyutilstest.cpp @@ -53,7 +53,7 @@ TEST_F(KeyUtilsTest, LancelotNotation) { TEST_F(KeyUtilsTest, KeyNameNotation) { // Invalid letter - // (actually valid in traditional german notation where B is H and Bb is B - + // (actually valid in traditional German notation where B is H and Bb is B - // everyone confused?) EXPECT_EQ(mixxx::track::io::key::INVALID, KeyUtils::guessKeyFromText("H")); @@ -142,6 +142,47 @@ TEST_F(KeyUtilsTest, KeyNameNotation) { KeyUtils::guessKeyFromText("cb")); EXPECT_EQ(mixxx::track::io::key::C_MINOR, KeyUtils::guessKeyFromText("b#")); + + // Rapid Evolution test cases + EXPECT_EQ(mixxx::track::io::key::A_MINOR, + KeyUtils::guessKeyFromText("Am")); + EXPECT_EQ(mixxx::track::io::key::A_MINOR, + KeyUtils::guessKeyFromText("08A")); + EXPECT_EQ(mixxx::track::io::key::B_FLAT_MINOR, + KeyUtils::guessKeyFromText("A#m")); + EXPECT_EQ(mixxx::track::io::key::B_FLAT_MINOR, + KeyUtils::guessKeyFromText("Bbm")); + EXPECT_EQ(mixxx::track::io::key::A_MAJOR, + KeyUtils::guessKeyFromText("11B")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("G#+50")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("Ab +50")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("Ab +50cents")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("04B +50cents")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("G#-50")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("Ab -50")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("Ab -50cents")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText("04B -50cents")); + EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + KeyUtils::guessKeyFromText(" 4b -50 cents ")); + // Mixxx does not allow this but Rapid Evolution + // EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + // KeyUtils::guessKeyFromText(" g # - 50 cents ")); + // EXPECT_EQ(mixxx::track::io::key::A_FLAT_MAJOR, // ionian + // KeyUtils::guessKeyFromText(" g # + 50 cents ")); + EXPECT_EQ(mixxx::track::io::key::INVALID, // ionian + KeyUtils::guessKeyFromText(" ")); + EXPECT_EQ(mixxx::track::io::key::INVALID, // ionian + KeyUtils::guessKeyFromText("")); + EXPECT_EQ(mixxx::track::io::key::INVALID, // ionian + KeyUtils::guessKeyFromText("xyz")); } mixxx::track::io::key::ChromaticKey incrementKey( From 009dba1083f2469a9361a8c93aaf7d1c32e614df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 24 Jan 2023 23:24:25 +0100 Subject: [PATCH 08/75] Make use of unique_ptr and std::move This avoids memory leaks --- src/library/banshee/bansheeplaylistmodel.cpp | 11 ++++++--- src/library/baseexternallibraryfeature.cpp | 4 +-- src/library/baseexternallibraryfeature.h | 8 +++--- src/library/basetrackcache.cpp | 18 +++++++------- src/library/basetrackcache.h | 10 ++++---- src/library/itunes/itunesfeature.cpp | 25 +++++++++++-------- src/library/itunes/itunesfeature.h | 3 ++- src/library/rekordbox/rekordboxfeature.cpp | 26 +++++++++++++------- src/library/rekordbox/rekordboxfeature.h | 5 ++-- src/library/rhythmbox/rhythmboxfeature.cpp | 12 ++++++--- src/library/serato/seratofeature.cpp | 19 +++++++++----- src/library/serato/seratofeature.h | 3 ++- src/library/traktor/traktorfeature.cpp | 19 +++++++++----- src/library/traktor/traktorfeature.h | 3 ++- 14 files changed, 104 insertions(+), 62 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index a934774478a..dffa749e468 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -187,6 +187,8 @@ void BansheePlaylistModel::setTableModel(int playlistId) { } } + const QString idColumn = CLM_TRACK_ID; + QStringList tableColumns; tableColumns << CLM_TRACK_ID // 0 @@ -215,10 +217,13 @@ void BansheePlaylistModel::setTableModel(int playlistId) { << CLM_COMPOSER; QSharedPointer trackSource( - new BaseTrackCache(m_pTrackCollectionManager->internalCollection(), m_tempTableName, CLM_TRACK_ID, - trackSourceColumns, false)); + new BaseTrackCache(m_pTrackCollectionManager->internalCollection(), + m_tempTableName, + idColumn, + std::move(trackSourceColumns), + false)); - setTable(m_tempTableName, CLM_TRACK_ID, tableColumns, trackSource); + setTable(m_tempTableName, idColumn, std::move(tableColumns), trackSource); setSearch(""); setDefaultSort(fieldIndex(PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder); setSort(defaultSortColumn(), defaultSortOrder()); diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 8f1ef33cd23..4a3b81a82ab 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -132,8 +132,8 @@ void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex( DEBUG_ASSERT(pPlaylist); *pPlaylist = m_lastRightClickedIndex.data().toString(); - QScopedPointer pPlaylistModelToAdd( - getPlaylistModelForPlaylist(*pPlaylist)); + std::unique_ptr pPlaylistModelToAdd( + createPlaylistModelForPlaylist(*pPlaylist)); if (!pPlaylistModelToAdd || !pPlaylistModelToAdd->initialized()) { qDebug() << "BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex " diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index 97ab683c09c..42333a5b847 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -3,9 +3,10 @@ #include #include #include +#include -#include "library/libraryfeature.h" #include "library/dao/playlistdao.h" +#include "library/libraryfeature.h" #include "util/parented_ptr.h" class BaseSqlTableModel; @@ -26,9 +27,10 @@ class BaseExternalLibraryFeature : public LibraryFeature { protected: // Must be implemented by external Libraries copied to Mixxx DB - virtual BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) { + virtual std::unique_ptr createPlaylistModelForPlaylist( + const QString& playlist) { Q_UNUSED(playlist); - return nullptr; + return {}; } // Must be implemented by external Libraries not copied to Mixxx DB virtual void appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist); diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp index 24c325fe8ec..ed46b46fc6e 100644 --- a/src/library/basetrackcache.cpp +++ b/src/library/basetrackcache.cpp @@ -17,15 +17,15 @@ constexpr bool sDebug = false; } // namespace BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, - const QString& tableName, - const QString& idColumn, - const QStringList& columns, - bool isCaching) - : m_tableName(tableName), - m_idColumn(idColumn), + QString tableName, + QString idColumn, + QStringList columns, + bool isCaching) + : m_tableName(std::move(tableName)), + m_idColumn(std::move(idColumn)), m_columnCount(columns.size()), m_columnsJoined(columns.join(",")), - m_columnCache(columns), + m_columnCache(std::move(columns)), m_pQueryParser(new SearchQueryParser(pTrackCollection)), m_bIndexBuilt(false), m_bIsCaching(isCaching), @@ -125,8 +125,8 @@ void BaseTrackCache::ensureCached(const QSet& trackIds) { updateTracksInIndex(trackIds); } -void BaseTrackCache::setSearchColumns(const QStringList& columns) { - m_searchColumns = columns; +void BaseTrackCache::setSearchColumns(QStringList columns) { + m_searchColumns = std::move(columns); } const TrackPointer& BaseTrackCache::getRecentTrack(TrackId trackId) const { diff --git a/src/library/basetrackcache.h b/src/library/basetrackcache.h index d4e957f2b6f..aa1f005db3d 100644 --- a/src/library/basetrackcache.h +++ b/src/library/basetrackcache.h @@ -43,10 +43,10 @@ class BaseTrackCache : public QObject { /// The order of the `columns` list parameter defines the initial/default /// order of columns in the library view. BaseTrackCache(TrackCollection* pTrackCollection, - const QString& tableName, - const QString& idColumn, - const QStringList& columns, - bool isCaching); + QString tableName, + QString idColumn, + QStringList columns, + bool isCaching); ~BaseTrackCache() override; // Rebuild the BaseTrackCache index from the SQL table. This can be @@ -73,7 +73,7 @@ class BaseTrackCache : public QObject { virtual bool isCached(TrackId trackId) const; virtual void ensureCached(TrackId trackId); virtual void ensureCached(const QSet& trackIds); - virtual void setSearchColumns(const QStringList& columns); + virtual void setSearchColumns(QStringList columns); signals: void tracksChanged(const QSet& trackIds); diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index e65a0373889..0c25ae22223 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -85,9 +85,12 @@ ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) << "bpm" << "rating"; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pLibrary->trackCollections()->internalCollection(), tableName, idColumn, - columns, false)); + m_trackSource = QSharedPointer(new BaseTrackCache( + m_pLibrary->trackCollections()->internalCollection(), + std::move(tableName), + std::move(idColumn), + std::move(columns), + false)); m_pITunesTrackModel = new BaseExternalTrackModel( this, m_pLibrary->trackCollections(), "mixxx.db.model.itunes", @@ -122,13 +125,15 @@ ITunesFeature::~ITunesFeature() { delete m_pITunesPlaylistModel; } -BaseSqlTableModel* ITunesFeature::getPlaylistModelForPlaylist(const QString& playlist) { - BaseExternalPlaylistModel* pModel = new BaseExternalPlaylistModel( - this, m_pLibrary->trackCollections(), - "mixxx.db.model.itunes_playlist", - "itunes_playlists", - "itunes_playlist_tracks", - m_trackSource); +std::unique_ptr +ITunesFeature::createPlaylistModelForPlaylist(const QString& playlist) { + std::unique_ptr pModel = + std::make_unique(this, + m_pLibrary->trackCollections(), + "mixxx.db.model.itunes_playlist", + "itunes_playlists", + "itunes_playlist_tracks", + m_trackSource); pModel->setPlaylist(playlist); return pModel; } diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h index a3cd26b1ffe..f72d58faf52 100644 --- a/src/library/itunes/itunesfeature.h +++ b/src/library/itunes/itunesfeature.h @@ -37,7 +37,8 @@ class ITunesFeature : public BaseExternalLibraryFeature { void onTrackCollectionLoaded(); private: - BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; + std::unique_ptr createPlaylistModelForPlaylist( + const QString& playlist) override; static QString getiTunesMusicPath(); // returns the invisible rootItem for the sidebar model TreeItem* importLibrary(); diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 5cddf0637e6..399b56a3d0a 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1250,8 +1250,7 @@ RekordboxFeature::RekordboxFeature( << LIBRARYTABLE_KEY << LIBRARYTABLE_COLOR << REKORDBOX_ANALYZE_PATH; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, tableName, idColumn, columns, false)); + QStringList searchColumns; searchColumns << LIBRARYTABLE_ARTIST @@ -1266,9 +1265,17 @@ RekordboxFeature::RekordboxFeature( << LIBRARYTABLE_BITRATE << LIBRARYTABLE_BPM << LIBRARYTABLE_KEY; + + m_trackSource = QSharedPointer( + new BaseTrackCache(m_pTrackCollection, + tableName, + std::move(idColumn), + std::move(columns), + false)); m_trackSource->setSearchColumns(searchColumns); - m_pRekordboxPlaylistModel = new RekordboxPlaylistModel(this, pLibrary->trackCollections(), m_trackSource); + m_pRekordboxPlaylistModel = make_parented( + this, pLibrary->trackCollections(), m_trackSource); m_title = tr("Rekordbox"); @@ -1308,8 +1315,6 @@ RekordboxFeature::~RekordboxFeature() { dropTable(database, kRekordboxPlaylistsTable); dropTable(database, kRekordboxLibraryTable); transaction.commit(); - - delete m_pRekordboxPlaylistModel; } void RekordboxFeature::bindLibraryWidget(WLibrary* libraryWidget, @@ -1330,10 +1335,13 @@ void RekordboxFeature::htmlLinkClicked(const QUrl& link) { } } -BaseSqlTableModel* RekordboxFeature::getPlaylistModelForPlaylist(const QString& playlist) { - RekordboxPlaylistModel* model = new RekordboxPlaylistModel(this, m_pLibrary->trackCollections(), m_trackSource); - model->setPlaylist(playlist); - return model; +std::unique_ptr +RekordboxFeature::createPlaylistModelForPlaylist(const QString& playlist) { + std::unique_ptr pModel = + std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); + pModel->setPlaylist(playlist); + return pModel; } QVariant RekordboxFeature::title() { diff --git a/src/library/rekordbox/rekordboxfeature.h b/src/library/rekordbox/rekordboxfeature.h index c1388cef3f1..476bae1ec00 100644 --- a/src/library/rekordbox/rekordboxfeature.h +++ b/src/library/rekordbox/rekordboxfeature.h @@ -78,10 +78,11 @@ class RekordboxFeature : public BaseExternalLibraryFeature { private: QString formatRootViewHtml() const; - BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; + std::unique_ptr createPlaylistModelForPlaylist( + const QString& playlist) override; TreeItemModel m_childModel; - RekordboxPlaylistModel* m_pRekordboxPlaylistModel; + parented_ptr m_pRekordboxPlaylistModel; QFutureWatcher> m_devicesFutureWatcher; QFuture> m_devicesFuture; diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index 6663b97a7e6..ba8f72d2d2c 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -34,9 +34,6 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfi << "duration" << "bitrate" << "bpm"; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, - tableName, idColumn, columns, false)); QStringList searchColumns; searchColumns << "artist" << "album" @@ -44,7 +41,14 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfi << "comment" << "title" << "genre"; - m_trackSource->setSearchColumns(searchColumns); + + m_trackSource = QSharedPointer( + new BaseTrackCache(m_pTrackCollection, + tableName, + std::move(idColumn), + std::move(columns), + false)); + m_trackSource->setSearchColumns(std::move(searchColumns)); m_pRhythmboxTrackModel = new BaseExternalTrackModel( this, pLibrary->trackCollections(), diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index ec9c6d6dcd8..be9e789836a 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -885,8 +885,12 @@ SeratoFeature::SeratoFeature( << LIBRARYTABLE_KEY; m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, kSeratoLibraryTable, LIBRARYTABLE_ID, columns, false)); - m_trackSource->setSearchColumns(searchColumns); + new BaseTrackCache(m_pTrackCollection, + kSeratoLibraryTable, + std::move(idColumn), + std::move(columns), + false)); + m_trackSource->setSearchColumns(std::move(searchColumns)); m_pSeratoPlaylistModel = new SeratoPlaylistModel(this, pLibrary->trackCollections(), m_trackSource); m_title = tr("Serato"); @@ -950,10 +954,13 @@ void SeratoFeature::htmlLinkClicked(const QUrl& link) { } } -BaseSqlTableModel* SeratoFeature::getPlaylistModelForPlaylist(const QString& playlist) { - SeratoPlaylistModel* model = new SeratoPlaylistModel(this, m_pLibrary->trackCollections(), m_trackSource); - model->setPlaylist(playlist); - return model; +std::unique_ptr +SeratoFeature::createPlaylistModelForPlaylist(const QString& playlist) { + std::unique_ptr pModel = + std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); + pModel->setPlaylist(playlist); + return pModel; } QVariant SeratoFeature::title() { diff --git a/src/library/serato/seratofeature.h b/src/library/serato/seratofeature.h index 515add942e8..18ba2b00a3c 100644 --- a/src/library/serato/seratofeature.h +++ b/src/library/serato/seratofeature.h @@ -48,7 +48,8 @@ class SeratoFeature : public BaseExternalLibraryFeature { private: QString formatRootViewHtml() const; - BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; + std::unique_ptr createPlaylistModelForPlaylist( + const QString& playlist) override; TreeItemModel m_childModel; SeratoPlaylistModel* m_pSeratoPlaylistModel; diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 35f77ab0039..b472b1ce654 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -84,9 +84,6 @@ TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) << "bitrate" << "bpm" << "key"; - m_trackSource = QSharedPointer( - new BaseTrackCache(pLibrary->trackCollections()->internalCollection(), tableName, idColumn, - columns, false)); QStringList searchColumns; searchColumns << "artist" << "album" @@ -94,7 +91,14 @@ TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) << "comment" << "title" << "genre"; - m_trackSource->setSearchColumns(searchColumns); + + m_trackSource = QSharedPointer(new BaseTrackCache( + pLibrary->trackCollections()->internalCollection(), + tableName, + std::move(idColumn), + std::move(columns), + false)); + m_trackSource->setSearchColumns(std::move(searchColumns)); m_isActivated = false; m_pTraktorTableModel = new TraktorTrackModel(this, pLibrary->trackCollections(), m_trackSource); @@ -124,8 +128,11 @@ TraktorFeature::~TraktorFeature() { delete m_pTraktorPlaylistModel; } -BaseSqlTableModel* TraktorFeature::getPlaylistModelForPlaylist(const QString& playlist) { - TraktorPlaylistModel* pModel = new TraktorPlaylistModel(this, m_pLibrary->trackCollections(), m_trackSource); +std::unique_ptr +TraktorFeature::createPlaylistModelForPlaylist(const QString& playlist) { + std::unique_ptr pModel = + std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); pModel->setPlaylist(playlist); return pModel; } diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index b685eb11937..9ef67de2599 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -47,7 +47,8 @@ class TraktorFeature : public BaseExternalLibraryFeature { void onTrackCollectionLoaded(); private: - BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; + std::unique_ptr createPlaylistModelForPlaylist( + const QString& playlist) override; TreeItem* importLibrary(const QString& file); // parses a track in the music collection void parseTrack(QXmlStreamReader &xml, QSqlQuery &query); From c6ea8ab74d17c789bb5969d462f51c5098554685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 25 Jan 2023 07:53:41 +0100 Subject: [PATCH 09/75] Use std::move in BaseSqlTableModel::setTable --- src/library/basesqltablemodel.cpp | 12 ++++++------ src/library/basesqltablemodel.h | 7 ++++--- src/library/hiddentablemodel.cpp | 6 ++++-- src/library/librarytablemodel.cpp | 6 ++++-- src/library/missingtablemodel.cpp | 6 ++++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/library/basesqltablemodel.cpp b/src/library/basesqltablemodel.cpp index 8a72b702d9f..a8bc7c9ed47 100644 --- a/src/library/basesqltablemodel.cpp +++ b/src/library/basesqltablemodel.cpp @@ -334,16 +334,16 @@ void BaseSqlTableModel::select() { << m_rowInfo.size(); } -void BaseSqlTableModel::setTable(const QString& tableName, - const QString& idColumn, - const QStringList& tableColumns, +void BaseSqlTableModel::setTable(QString tableName, + QString idColumn, + QStringList tableColumns, QSharedPointer trackSource) { if (sDebug) { qDebug() << this << "setTable" << tableName << tableColumns << idColumn; } - m_tableName = tableName; - m_idColumn = idColumn; - m_tableColumns = tableColumns; + m_tableName = std::move(tableName); + m_idColumn = std::move(idColumn); + m_tableColumns = std::move(tableColumns); if (m_trackSource) { disconnect(m_trackSource.data(), diff --git a/src/library/basesqltablemodel.h b/src/library/basesqltablemodel.h index a7c46f60897..a2076476eba 100644 --- a/src/library/basesqltablemodel.h +++ b/src/library/basesqltablemodel.h @@ -84,9 +84,10 @@ class BaseSqlTableModel : public BaseTrackTableModel { const QVariant& value, int role) final; - void setTable(const QString& tableName, const QString& trackIdColumn, - const QStringList& tableColumns, - QSharedPointer trackSource); + void setTable(QString tableName, + QString trackIdColumn, + QStringList tableColumns, + QSharedPointer trackSource); void initHeaderProperties() override; virtual void initSortColumnMapping(); diff --git a/src/library/hiddentablemodel.cpp b/src/library/hiddentablemodel.cpp index 3a2b3425ffb..adcb7008cce 100644 --- a/src/library/hiddentablemodel.cpp +++ b/src/library/hiddentablemodel.cpp @@ -40,8 +40,10 @@ void HiddenTableModel::setTableModel(int id) { QStringList tableColumns; tableColumns << LIBRARYTABLE_ID; - setTable(tableName, LIBRARYTABLE_ID, tableColumns, - m_pTrackCollectionManager->internalCollection()->getTrackSource()); + setTable(tableName, + LIBRARYTABLE_ID, + std::move(tableColumns), + m_pTrackCollectionManager->internalCollection()->getTrackSource()); setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder); setSearch(""); } diff --git a/src/library/librarytablemodel.cpp b/src/library/librarytablemodel.cpp index 3921a493c6a..dbb2c397272 100644 --- a/src/library/librarytablemodel.cpp +++ b/src/library/librarytablemodel.cpp @@ -50,8 +50,10 @@ void LibraryTableModel::setTableModel(int id) { tableColumns << LIBRARYTABLE_ID; tableColumns << LIBRARYTABLE_PREVIEW; tableColumns << LIBRARYTABLE_COVERART; - setTable(tableName, LIBRARYTABLE_ID, tableColumns, - m_pTrackCollectionManager->internalCollection()->getTrackSource()); + setTable(tableName, + LIBRARYTABLE_ID, + std::move(tableColumns), + m_pTrackCollectionManager->internalCollection()->getTrackSource()); setSearch(""); setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder); diff --git a/src/library/missingtablemodel.cpp b/src/library/missingtablemodel.cpp index 6e4af6cab52..fc42a67757b 100644 --- a/src/library/missingtablemodel.cpp +++ b/src/library/missingtablemodel.cpp @@ -46,8 +46,10 @@ void MissingTableModel::setTableModel(int id) { QStringList tableColumns; tableColumns << LIBRARYTABLE_ID; - setTable(tableName, LIBRARYTABLE_ID, tableColumns, - m_pTrackCollectionManager->internalCollection()->getTrackSource()); + setTable(tableName, + LIBRARYTABLE_ID, + std::move(tableColumns), + m_pTrackCollectionManager->internalCollection()->getTrackSource()); setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder); setSearch(""); From b6c82afcdb732aae864e2bb835b782c075f584c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 24 Jan 2023 23:26:16 +0100 Subject: [PATCH 10/75] Inmprove initialization of library columns --- src/library/banshee/bansheeplaylistmodel.cpp | 50 ++++++++-------- src/library/itunes/itunesfeature.cpp | 32 +++++----- src/library/rekordbox/rekordboxfeature.cpp | 63 ++++++++++---------- src/library/rhythmbox/rhythmboxfeature.cpp | 42 ++++++------- src/library/serato/seratofeature.cpp | 63 ++++++++++---------- src/library/traktor/traktorfeature.cpp | 44 +++++++------- 6 files changed, 145 insertions(+), 149 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index dffa749e468..e5039311fe1 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -189,32 +189,30 @@ void BansheePlaylistModel::setTableModel(int playlistId) { const QString idColumn = CLM_TRACK_ID; - QStringList tableColumns; - tableColumns - << CLM_TRACK_ID // 0 - << CLM_VIEW_ORDER - << CLM_PREVIEW; // 3 - - QStringList trackSourceColumns; - trackSourceColumns - << CLM_TRACK_ID // 0 - << CLM_ARTIST - << CLM_TITLE - << CLM_DURATION - << CLM_URI - << CLM_ALBUM - << CLM_ALBUM_ARTIST - << CLM_YEAR - << CLM_RATING - << CLM_GENRE - << CLM_GROUPING - << CLM_TRACKNUMBER - << CLM_DATEADDED - << CLM_BPM - << CLM_BITRATE - << CLM_COMMENT - << CLM_PLAYCOUNT - << CLM_COMPOSER; + QStringList tableColumns = { + CLM_TRACK_ID, + CLM_VIEW_ORDER, + CLM_PREVIEW}; // 3 + + QStringList trackSourceColumns = { + CLM_TRACK_ID, // 0 + CLM_ARTIST, + CLM_TITLE, + CLM_DURATION, + CLM_URI, + CLM_ALBUM, + CLM_ALBUM_ARTIST, + CLM_YEAR, + CLM_RATING, + CLM_GENRE, + CLM_GROUPING, + CLM_TRACKNUMBER, + CLM_DATEADDED, + CLM_BPM, + CLM_BITRATE, + CLM_COMMENT, + CLM_PLAYCOUNT, + CLM_COMPOSER}; QSharedPointer trackSource( new BaseTrackCache(m_pTrackCollectionManager->internalCollection(), diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 0c25ae22223..42b44e94a3a 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -68,22 +68,22 @@ ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) m_icon(":/images/library/ic_library_itunes.svg") { QString tableName = "itunes_library"; QString idColumn = "id"; - QStringList columns; - columns << "id" - << "artist" - << "title" - << "album" - << "album_artist" - << "year" - << "genre" - << "grouping" - << "tracknumber" - << "location" - << "comment" - << "duration" - << "bitrate" - << "bpm" - << "rating"; + QStringList columns = { + "id", + "artist", + "title", + "album", + "album_artist", + "year", + "genre", + "grouping", + "tracknumber", + "location", + "comment", + "duration", + "bitrate", + "bpm", + "rating"}; m_trackSource = QSharedPointer(new BaseTrackCache( m_pLibrary->trackCollections()->internalCollection(), diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 399b56a3d0a..7163b64c55b 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1233,38 +1233,37 @@ RekordboxFeature::RekordboxFeature( m_icon(":/images/library/ic_library_rekordbox.svg") { QString tableName = kRekordboxLibraryTable; QString idColumn = LIBRARYTABLE_ID; - QStringList columns; - columns << LIBRARYTABLE_ID - << LIBRARYTABLE_ARTIST - << LIBRARYTABLE_TITLE - << LIBRARYTABLE_ALBUM - << LIBRARYTABLE_YEAR - << LIBRARYTABLE_GENRE - << LIBRARYTABLE_TRACKNUMBER - << TRACKLOCATIONSTABLE_LOCATION - << LIBRARYTABLE_COMMENT - << LIBRARYTABLE_RATING - << LIBRARYTABLE_DURATION - << LIBRARYTABLE_BITRATE - << LIBRARYTABLE_BPM - << LIBRARYTABLE_KEY - << LIBRARYTABLE_COLOR - << REKORDBOX_ANALYZE_PATH; - - QStringList searchColumns; - searchColumns - << LIBRARYTABLE_ARTIST - << LIBRARYTABLE_TITLE - << LIBRARYTABLE_ALBUM - << LIBRARYTABLE_YEAR - << LIBRARYTABLE_GENRE - << LIBRARYTABLE_TRACKNUMBER - << TRACKLOCATIONSTABLE_LOCATION - << LIBRARYTABLE_COMMENT - << LIBRARYTABLE_DURATION - << LIBRARYTABLE_BITRATE - << LIBRARYTABLE_BPM - << LIBRARYTABLE_KEY; + QStringList columns = { + LIBRARYTABLE_ID, + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_YEAR, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_TRACKNUMBER, + TRACKLOCATIONSTABLE_LOCATION, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_RATING, + LIBRARYTABLE_DURATION, + LIBRARYTABLE_BITRATE, + LIBRARYTABLE_BPM, + LIBRARYTABLE_KEY, + LIBRARYTABLE_COLOR, + REKORDBOX_ANALYZE_PATH}; + + const QStringList searchColumns = { + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_YEAR, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_TRACKNUMBER, + TRACKLOCATIONSTABLE_LOCATION, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_DURATION, + LIBRARYTABLE_BITRATE, + LIBRARYTABLE_BPM, + LIBRARYTABLE_KEY}; m_trackSource = QSharedPointer( new BaseTrackCache(m_pTrackCollection, diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index ba8f72d2d2c..c55e5f2720e 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -20,27 +20,27 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfi m_icon(":/images/library/ic_library_rhythmbox.svg") { QString tableName = "rhythmbox_library"; QString idColumn = "id"; - QStringList columns; - columns << "id" - << "artist" - << "title" - << "album" - << "year" - << "genre" - << "tracknumber" - << "location" - << "comment" - << "rating" - << "duration" - << "bitrate" - << "bpm"; - QStringList searchColumns; - searchColumns << "artist" - << "album" - << "location" - << "comment" - << "title" - << "genre"; + QStringList columns = { + "id", + "artist", + "title", + "album", + "year", + "genre", + "tracknumber", + "location", + "comment", + "rating", + "duration", + "bitrate", + "bpm"}; + QStringList searchColumns = { + "artist", + "album", + "location", + "comment", + "title", + "genre"}; m_trackSource = QSharedPointer( new BaseTrackCache(m_pTrackCollection, diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index be9e789836a..9ab30932bb1 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -851,38 +851,37 @@ SeratoFeature::SeratoFeature( UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), m_icon(":/images/library/ic_library_serato.svg") { - QStringList columns; - columns << LIBRARYTABLE_ID - << LIBRARYTABLE_TITLE - << LIBRARYTABLE_ARTIST - << LIBRARYTABLE_ALBUM - << LIBRARYTABLE_GENRE - << LIBRARYTABLE_COMMENT - << LIBRARYTABLE_GROUPING - << LIBRARYTABLE_YEAR - << LIBRARYTABLE_DURATION - << LIBRARYTABLE_BITRATE - << LIBRARYTABLE_SAMPLERATE - << LIBRARYTABLE_BPM - << LIBRARYTABLE_KEY - << LIBRARYTABLE_TRACKNUMBER - << TRACKLOCATIONSTABLE_LOCATION - << LIBRARYTABLE_BPM_LOCK; - - QStringList searchColumns; - searchColumns - << LIBRARYTABLE_ARTIST - << LIBRARYTABLE_TITLE - << LIBRARYTABLE_ALBUM - << LIBRARYTABLE_YEAR - << LIBRARYTABLE_GENRE - << LIBRARYTABLE_TRACKNUMBER - << TRACKLOCATIONSTABLE_LOCATION - << LIBRARYTABLE_COMMENT - << LIBRARYTABLE_DURATION - << LIBRARYTABLE_BITRATE - << LIBRARYTABLE_BPM - << LIBRARYTABLE_KEY; + QString idColumn = LIBRARYTABLE_ID; + QStringList columns = { + LIBRARYTABLE_ID, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_GROUPING, + LIBRARYTABLE_YEAR, + LIBRARYTABLE_DURATION, + LIBRARYTABLE_BITRATE, + LIBRARYTABLE_SAMPLERATE, + LIBRARYTABLE_BPM, + LIBRARYTABLE_KEY, + LIBRARYTABLE_TRACKNUMBER, + TRACKLOCATIONSTABLE_LOCATION, + LIBRARYTABLE_BPM_LOCK}; + QStringList searchColumns = { + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_YEAR, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_TRACKNUMBER, + TRACKLOCATIONSTABLE_LOCATION, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_DURATION, + LIBRARYTABLE_BITRATE, + LIBRARYTABLE_BPM, + LIBRARYTABLE_KEY}; m_trackSource = QSharedPointer( new BaseTrackCache(m_pTrackCollection, diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index b472b1ce654..d71ba0f3e69 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -69,28 +69,28 @@ TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) m_icon(":/images/library/ic_library_traktor.svg") { QString tableName = "traktor_library"; QString idColumn = "id"; - QStringList columns; - columns << "id" - << "artist" - << "title" - << "album" - << "year" - << "genre" - << "tracknumber" - << "location" - << "comment" - << "rating" - << "duration" - << "bitrate" - << "bpm" - << "key"; - QStringList searchColumns; - searchColumns << "artist" - << "album" - << "location" - << "comment" - << "title" - << "genre"; + QStringList columns = { + "id", + "artist", + "title", + "album", + "year", + "genre", + "tracknumber", + "location", + "comment", + "rating", + "duration", + "bitrate", + "bpm", + "key"}; + QStringList searchColumns = { + "artist", + "album", + "location", + "comment", + "title", + "genre"}; m_trackSource = QSharedPointer(new BaseTrackCache( pLibrary->trackCollections()->internalCollection(), From 8bd952a0718fcaa86b0681d32652a2a298d4ba48 Mon Sep 17 00:00:00 2001 From: holopansel Date: Wed, 25 Jan 2023 14:53:40 +0100 Subject: [PATCH 11/75] modifications as suggested by swiftboy --- res/controllers/Denon-MC7000-scripts.js | 202 ++++++++---------------- 1 file changed, 64 insertions(+), 138 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index fc0e3ca4414..57dbd839c84 100644 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -155,74 +155,8 @@ MC7000.paramButton = [0, 0, 0, 0]; /* color codes: - -0x followed by - - -01 off -02 dark blue -03 blue -04 bright blue -05 dark green -06 dark cyan -07 dark middle blue -08 bright blue -09 middle green -0A middle light green -0B middle cyan -0C middle blue -0D bright green -0E bright middle green -0F bright light green -10 bright cyan -11 dark red -12 dark pink -13 dark purple -14 middle purple blue -15 dark yellow -16 dark white -17 dark light blue -18 middle light blue -19 dark green/yellow -1A dark light green -1B dark light cyan -1C middle light blue -1D bright green -1E bright light green -1F bright light green -20 bright light cyan -21 middle red -22 middle pink -23 middle dark pink -24 middle purple -25 dark orange -26 dark light rose -27 dark light pink/purple -28 dark purple blue -29 dark yellow -2A dark light yellow -2B dark white -2C middle light blue -2D middle green -2E middle light green -2F middle light light green -30 middle cyan -31 bright red -32 bright pink/red -33 bright pink -34 bright pink/purple -35 bright orange amber -36 bright pink/red -37 bright pink -38 bright pink/purple -39 bright orange -3A bright light orange -3B bright light rose -3C bright light pink/purple -3D bright yellow -3E bright light yellow -3F bright light light yellow -40 bright white +colors are encoded using the following schema: Take the individual components of the color (R, G, B). Then use +the two most significant bits of that color (rr, gg, bb) and pack that into a 7-byte integer using the following schema `0b0rrggbb`. Then add 1 before sending to the controller. */ /* @@ -362,11 +296,8 @@ MC7000.padModeCue = function(channel, control, value, status, group) { MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Hot Cue Mode for (var i = 1; i <= 8; i++) { - if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); - } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); - } + var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } }; @@ -388,7 +319,7 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - MC7000.sendColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Flip @@ -409,7 +340,7 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - MC7000.sendColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Roll @@ -430,7 +361,7 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Roll Mode - MC7000.sendColor(deckOffset, MC7000.padColor.rolloff); + MC7000.setPadColor(deckOffset, MC7000.padColor.rolloff); }; // PAD Mode Saved Loop @@ -475,7 +406,7 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // change PAD color when switching to Slicer Mode - MC7000.sendColor(deckOffset, MC7000.padColor.sliceron); + MC7000.setPadColor(deckOffset, MC7000.padColor.sliceron); }; // PAD Mode Slicer Loop @@ -496,7 +427,7 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckNumber] = false; MC7000.PADModePitch[deckNumber] = false; // switch off PAD illumination - MC7000.sendColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; // PAD Mode Sampler @@ -591,10 +522,9 @@ MC7000.padModePitch = function(channel, control, value, status, group) { for (var i = 1; i <= 8; i++) { if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); - } else if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); + var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } } }; @@ -688,6 +618,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { if (control === 0x14 + i - 1 && value >= 0x01) { if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerloaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck @@ -695,12 +626,14 @@ MC7000.PadButtons = function(channel, control, value, status, group) { samplerOffsetJ = deckOffset * 8 + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + j - 1, MC7000.padColor.samplerloaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); } } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler if (MC7000.SamplerQty === 16) { @@ -731,6 +664,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { if (control === 0x14 + i - 1 && value >= 0x01) { if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { // if sampler is not loaded, load sampler and set color to loaded engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsamploaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck @@ -738,12 +672,14 @@ MC7000.PadButtons = function(channel, control, value, status, group) { samplerOffsetJ = deckOffset * 8 + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + j - 1, MC7000.padColor.velsamploaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", script.absoluteNonLin(value, 0, 1.0, 4.0)); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); } } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); @@ -766,26 +702,27 @@ MC7000.PadButtons = function(channel, control, value, status, group) { if (engine.getValue(group, "track_loaded") === 1) { for (i = 1; i <= 8; i++) { // intermediate variables - var ButtonPressed = (value === 0x7F), ButtonReleased = (value === 0x00), ControlNumber1 = (control === 0x14 + i -1), ControlNumber2 = (control === 0x1C + i -1); - var HotcueOn = engine.getValue(group, "hotcue_" + i + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckOffset]; - if (ButtonPressed && ControlNumber1) { + var isButtonPressed = (value === 0x7F); + var isButtonReleased = (value === 0x00); + var isControlAddress = (control === 0x14 + i -1); + var isControlAddressShift = (control === 0x1C + i -1); + var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckOffset]; + if (isButtonPressed && isControlAddress) { if (!HotcueSelectedOnDeck) { - if (!HotcueOn) { //hotcue select if none available + MC7000.setPadColor(deckOffset, MC7000.padColor.pitchoff); + MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch + if (!hotcueEnabled) { //hotcue select if none available engine.setValue(group, "hotcue_" + i + "_activate", true); // set hotcue if not set before - MC7000.HotcueSelectedGroup[deckOffset] = i; - MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); - } else { // hotcue select if available - MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch - MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); } } else { // hotcue selected and button pressed // TODO: play if play, stop if cue engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop - MC7000.sendColor(deckOffset, MC7000.padColor.pitchoff); + MC7000.setPadColor(deckOffset, MC7000.padColor.pitchoff); engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckNumber-1][i-1]); engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color + midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.pitchon); // keep color when shift is pressed } - } else if (ButtonReleased && ControlNumber1) { // button release change color and stop play + } else if (isButtonReleased && isControlAddress) { // button release change color and stop play // engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop //TODO if for setting continue to play or stop on button release // midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); // switch to pitch off color if (engine.getValue(group, "slip_enabled")) { @@ -794,15 +731,13 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue(group, "slip_enabled", true); }, true); } - } else if (ButtonPressed && ControlNumber2) { //shifted buttons deselect hotcue for pitch + } else if (isButtonPressed && isControlAddressShift) { //shifted buttons deselect hotcue for pitch engine.setValue(group, "pitch", 0); MC7000.HotcueSelectedGroup[deckOffset] = 0; for (z = 1; z <= 8; z++) { - if (engine.getValue(group, "hotcue_" + z + "_enabled", true)) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.hotcueon); - } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, MC7000.padColor.hotcueoff); - } + hotcueEnabled = engine.getValue(group, "hotcue_" + z + "_enabled", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed } } // end else if } // end for @@ -811,9 +746,11 @@ MC7000.PadButtons = function(channel, control, value, status, group) { }; //end pad buttons -MC7000.sendColor = function(sendColorDeckOffset, ColorCode) { - for (var z = 1; z <= 8; z++) { - midi.sendShortMsg(0x94 + sendColorDeckOffset, 0x14 + z - 1, ColorCode); // switch 8 buttons to selected color +MC7000.setPadColor = function(deckOffset, colorValue) { + for (var z = 0; z < 8; z++) { + // switch 8 buttons to selected color + midi.sendShortMsg(0x94 + deckOffset, 0x14 + z, colorValue); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + z, colorValue); // keep color when shift is pressed } }; @@ -1140,8 +1077,8 @@ MC7000.StarsDown = function(channel, control, value, status, group) { //return; // don't respond to note off messages } else { if (MC7000.PADModePitch[deckNumber]) { - for (var i = 1; i <= 8; i++) { - MC7000.halftoneToPadMap[deckNumber-1][i-1] = MC7000.halftoneToPadMap[deckNumber-1][i-1] - 8; // pitch down + for (var i = 0; i < 8; i++) { + MC7000.halftoneToPadMap[deckNumber-1][i] = MC7000.halftoneToPadMap[deckNumber-1][i] - 8; // pitch down } } else { engine.setValue(group, "stars_down", true); // stars down @@ -1156,8 +1093,8 @@ MC7000.StarsUp = function(channel, control, value, status, group) { //return; // don't respond to note off messages } else { if (MC7000.PADModePitch[deckNumber]) { - for (var i = 1; i <= 8; i++) { - MC7000.halftoneToPadMap[deckNumber-1][i-1] = MC7000.halftoneToPadMap[deckNumber-1][i-1] + 8; // pitch up + for (var i = 0; i < 8; i++) { + MC7000.halftoneToPadMap[deckNumber-1][i] = MC7000.halftoneToPadMap[deckNumber-1][i] + 8; // pitch up } } else { engine.setValue(group, "stars_up", true); // stars up @@ -1277,10 +1214,12 @@ MC7000.HotCueLED = function(value, group) { if (value === 1) { if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueon); } } else { if (engine.getValue(group, "hotcue_"+i+"_enabled") === 0) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueoff); } } } @@ -1289,27 +1228,19 @@ MC7000.HotCueLED = function(value, group) { // Sampler LED MC7000.SamplerLED = function() { - for (var j = 1; j <= 4; j++) { - for (var i = 1; i <= 8; i++) { + for (var j = 0; j < 4; j++) { + for (var i = 0; i < 8; i++) { var sampNo = 0; if (MC7000.PADModeSampler[j]) { if (MC7000.SamplerQty === 16) { - if (j >= 3) { - sampNo = (j - 3) * 8 + i; - } else { - sampNo = (j - 1) * 8 + i; - } + (j >= 2) ? sampNo = (j - 2) * 8 + i + 1 : sampNo = j * 8 + i + 1; } else if (MC7000.SamplerQty === 32) { - sampNo = (j - 1) * 8 + i; + sampNo = j * 8 + i + 1; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { - if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.samplerloaded); - } else { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.samplerplay); - } + (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) ? midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.samplerloaded) : midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.samplerplay); } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.sampleroff); + midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.sampleroff); } } } @@ -1318,28 +1249,24 @@ MC7000.SamplerLED = function() { // Velocity Sampler LED MC7000.VelSampLED = function() { - for (var j = 1; j <= 4; j++) { - for (var i = 1; i <= 8; i++) { + for (var j = 0; j < 4; j++) { + for (var i = 0; i < 8; i++) { var sampNo = 0; if (MC7000.PADModeVelSamp[j]) { if (MC7000.SamplerQty === 16) { - if (j >= 3) { - sampNo = (j - 3) * 8 + i; - } else { - sampNo = (j - 1) * 8 + i; - } + (j >= 2) ? sampNo = (j - 2) * 8 + i + 1: sampNo = j * 8 + i + 1; } else { - sampNo = (j - 1) * 8 + i; + sampNo = j * 8 + i + 1; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { - if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsamploaded); - engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); + var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; + if (samplerIsNotPlaying) { + midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.velsamploaded); engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); } else { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsampplay); + midi.sendShortMsg(0x94 + j, 0x14 + i - 1, MC7000.padColor.velsampplay); } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + j - 1, 0x14 + i - 1, MC7000.padColor.velsampoff); + midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.velsampoff); } } } @@ -1351,17 +1278,16 @@ MC7000.PitchLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; if (MC7000.PADModePitch[deckNumber]) { - for (var i = 1; i <= 8; i++) { + for (var i = 0; i < 8; i++) { if (engine.getValue("[Channel"+deckNumber+"]", "play") === 0) { // stopped if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { // hotcue selected - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); - } else if (engine.getValue(group, "hotcue_" + i + "_enabled", true)) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.pitchoff); } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); + var hotcueEnabled = engine.getValue(group, "hotcue_" + i + 1 + "_enabled", true); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); + midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.pitchon); } } } From adcb323e09d08e226e85626267c1cb4d5575d5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 25 Jan 2023 08:21:48 +0100 Subject: [PATCH 12/75] Move BaseTrackCache::setSearchColumns to constructor, to create the object at once. --- src/library/banshee/bansheeplaylistmodel.cpp | 11 +++ src/library/basetrackcache.cpp | 16 +--- src/library/basetrackcache.h | 2 +- src/library/dao/trackschema.h | 1 + src/library/itunes/itunesfeature.cpp | 10 +++ src/library/mixxxlibraryfeature.cpp | 92 +++++++++++--------- src/library/rekordbox/rekordboxfeature.cpp | 3 +- src/library/rhythmbox/rhythmboxfeature.cpp | 2 +- src/library/serato/seratofeature.cpp | 7 +- src/library/traktor/traktorfeature.cpp | 2 +- 10 files changed, 81 insertions(+), 65 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index e5039311fe1..edd1905b27c 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -34,6 +34,7 @@ #define CLM_PLAYCOUNT "timesplayed" #define CLM_COMPOSER "composer" #define CLM_PREVIEW "preview" +#define CLM_CRATE "crate" namespace { @@ -213,12 +214,22 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_COMMENT, CLM_PLAYCOUNT, CLM_COMPOSER}; + QStringList searchColumns = { + KArtist, + kAlbum, + kAlbumArtist, + kUri, + kGrouping, + kComment, + KTitel, + kGenre}; QSharedPointer trackSource( new BaseTrackCache(m_pTrackCollectionManager->internalCollection(), m_tempTableName, idColumn, std::move(trackSourceColumns), + std::move(searchColumns), false)); setTable(m_tempTableName, idColumn, std::move(tableColumns), trackSource); diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp index ed46b46fc6e..27bedea8b8e 100644 --- a/src/library/basetrackcache.cpp +++ b/src/library/basetrackcache.cpp @@ -20,6 +20,7 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, QString tableName, QString idColumn, QStringList columns, + QStringList searchColumns, bool isCaching) : m_tableName(std::move(tableName)), m_idColumn(std::move(idColumn)), @@ -27,19 +28,10 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, m_columnsJoined(columns.join(",")), m_columnCache(std::move(columns)), m_pQueryParser(new SearchQueryParser(pTrackCollection)), + m_searchColumns(std::move(searchColumns)), m_bIndexBuilt(false), m_bIsCaching(isCaching), m_database(pTrackCollection->database()) { - m_searchColumns << "artist" - << "album" - << "album_artist" - << "location" - << "grouping" - << "comment" - << "title" - << "genre" - << "crate"; - // Convert all the search column names to their field indexes because we use // them a bunch. m_searchColumnIndices.resize(m_searchColumns.size()); @@ -125,10 +117,6 @@ void BaseTrackCache::ensureCached(const QSet& trackIds) { updateTracksInIndex(trackIds); } -void BaseTrackCache::setSearchColumns(QStringList columns) { - m_searchColumns = std::move(columns); -} - const TrackPointer& BaseTrackCache::getRecentTrack(TrackId trackId) const { DEBUG_ASSERT(m_bIsCaching); // Only refresh the recently used track if the identifiers diff --git a/src/library/basetrackcache.h b/src/library/basetrackcache.h index aa1f005db3d..d99ef43af39 100644 --- a/src/library/basetrackcache.h +++ b/src/library/basetrackcache.h @@ -46,6 +46,7 @@ class BaseTrackCache : public QObject { QString tableName, QString idColumn, QStringList columns, + QStringList searchColumns, bool isCaching); ~BaseTrackCache() override; @@ -73,7 +74,6 @@ class BaseTrackCache : public QObject { virtual bool isCached(TrackId trackId) const; virtual void ensureCached(TrackId trackId); virtual void ensureCached(const QSet& trackIds); - virtual void setSearchColumns(QStringList columns); signals: void tracksChanged(const QSet& trackIds); diff --git a/src/library/dao/trackschema.h b/src/library/dao/trackschema.h index 100655df562..a5b694379a3 100644 --- a/src/library/dao/trackschema.h +++ b/src/library/dao/trackschema.h @@ -43,6 +43,7 @@ const QString LIBRARYTABLE_COVERART_SOURCE = QStringLiteral("coverart_source"); const QString LIBRARYTABLE_COVERART_TYPE = QStringLiteral("coverart_type"); const QString LIBRARYTABLE_COVERART_LOCATION = QStringLiteral("coverart_location"); const QString LIBRARYTABLE_COVERART_HASH = QStringLiteral("coverart_hash"); +const QString LIBRARYTABLE_CRATE = QStringLiteral("crate"); const QString TRACKLOCATIONSTABLE_ID = QStringLiteral("id"); const QString TRACKLOCATIONSTABLE_LOCATION = QStringLiteral("location"); diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 42b44e94a3a..b193ace2f20 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -84,12 +84,22 @@ ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) "bitrate", "bpm", "rating"}; + QStringList searchColumns = { + "artist", + "album", + "album_artist", + "location", + "grouping", + "comment", + "title", + "genre"}; m_trackSource = QSharedPointer(new BaseTrackCache( m_pLibrary->trackCollections()->internalCollection(), std::move(tableName), std::move(idColumn), std::move(columns), + std::move(searchColumns), false)); m_pITunesTrackModel = new BaseExternalTrackModel( this, m_pLibrary->trackCollections(), diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 33ea90143cb..ea4e0c2ee5e 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -20,44 +20,6 @@ #include "util/dnd.h" #include "widget/wlibrary.h" -namespace { - -const QStringList DEFAULT_COLUMNS = { - LIBRARYTABLE_ID, - LIBRARYTABLE_PLAYED, - LIBRARYTABLE_TIMESPLAYED, - //has to be up here otherwise Played and TimesPlayed are not shown - LIBRARYTABLE_ALBUMARTIST, - LIBRARYTABLE_ALBUM, - LIBRARYTABLE_ARTIST, - LIBRARYTABLE_TITLE, - LIBRARYTABLE_YEAR, - LIBRARYTABLE_RATING, - LIBRARYTABLE_GENRE, - LIBRARYTABLE_COMPOSER, - LIBRARYTABLE_GROUPING, - LIBRARYTABLE_TRACKNUMBER, - LIBRARYTABLE_KEY, - LIBRARYTABLE_KEY_ID, - LIBRARYTABLE_BPM, - LIBRARYTABLE_BPM_LOCK, - LIBRARYTABLE_DURATION, - LIBRARYTABLE_BITRATE, - LIBRARYTABLE_REPLAYGAIN, - LIBRARYTABLE_FILETYPE, - LIBRARYTABLE_DATETIMEADDED, - TRACKLOCATIONSTABLE_LOCATION, - TRACKLOCATIONSTABLE_FSDELETED, - LIBRARYTABLE_COMMENT, - LIBRARYTABLE_MIXXXDELETED, - LIBRARYTABLE_COLOR, - LIBRARYTABLE_COVERART_SOURCE, - LIBRARYTABLE_COVERART_TYPE, - LIBRARYTABLE_COVERART_LOCATION, - LIBRARYTABLE_COVERART_HASH}; - -} // namespace - MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, UserSettingsPointer pConfig) : LibraryFeature(pLibrary, pConfig), @@ -68,7 +30,51 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, m_pLibraryTableModel(nullptr), m_pMissingView(nullptr), m_pHiddenView(nullptr) { - QStringList columns = DEFAULT_COLUMNS; + QString idColumn = LIBRARYTABLE_ID; + QStringList columns = { + LIBRARYTABLE_ID, + LIBRARYTABLE_PLAYED, + LIBRARYTABLE_TIMESPLAYED, + // has to be up here otherwise Played and TimesPlayed are not shown + LIBRARYTABLE_ALBUMARTIST, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_YEAR, + LIBRARYTABLE_RATING, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_COMPOSER, + LIBRARYTABLE_GROUPING, + LIBRARYTABLE_TRACKNUMBER, + LIBRARYTABLE_KEY, + LIBRARYTABLE_KEY_ID, + LIBRARYTABLE_BPM, + LIBRARYTABLE_BPM_LOCK, + LIBRARYTABLE_DURATION, + LIBRARYTABLE_BITRATE, + LIBRARYTABLE_REPLAYGAIN, + LIBRARYTABLE_FILETYPE, + LIBRARYTABLE_DATETIMEADDED, + TRACKLOCATIONSTABLE_LOCATION, + TRACKLOCATIONSTABLE_FSDELETED, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_MIXXXDELETED, + LIBRARYTABLE_COLOR, + LIBRARYTABLE_COVERART_SOURCE, + LIBRARYTABLE_COVERART_TYPE, + LIBRARYTABLE_COVERART_LOCATION, + LIBRARYTABLE_COVERART_HASH}; + QStringList searchColumns = { + LIBRARYTABLE_ARTIST, + LIBRARYTABLE_ALBUM, + LIBRARYTABLE_ALBUMARTIST, + TRACKLOCATIONSTABLE_LOCATION, + LIBRARYTABLE_GROUPING, + LIBRARYTABLE_COMMENT, + LIBRARYTABLE_TITLE, + LIBRARYTABLE_GENRE, + LIBRARYTABLE_CRATE}; + QStringList qualifiedTableColumns; for (const auto& col : columns) { qualifiedTableColumns.append(mixxx::trackschema::tableForColumn(col) + @@ -87,8 +93,12 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, LOG_FAILED_QUERY(query); } - BaseTrackCache* pBaseTrackCache = new BaseTrackCache( - m_pTrackCollection, tableName, LIBRARYTABLE_ID, columns, true); + BaseTrackCache* pBaseTrackCache = new BaseTrackCache(m_pTrackCollection, + std::move(tableName), + std::move(idColumn), + std::move(columns), + std::move(searchColumns), + true); m_pBaseTrackCache = QSharedPointer(pBaseTrackCache); m_pTrackCollection->connectTrackSource(m_pBaseTrackCache); diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 7163b64c55b..ac403f97493 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1270,9 +1270,8 @@ RekordboxFeature::RekordboxFeature( tableName, std::move(idColumn), std::move(columns), + std::move(searchColumns), false)); - m_trackSource->setSearchColumns(searchColumns); - m_pRekordboxPlaylistModel = make_parented( this, pLibrary->trackCollections(), m_trackSource); diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index c55e5f2720e..468ac88bd20 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -47,8 +47,8 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfi tableName, std::move(idColumn), std::move(columns), + std::move(searchColumns), false)); - m_trackSource->setSearchColumns(std::move(searchColumns)); m_pRhythmboxTrackModel = new BaseExternalTrackModel( this, pLibrary->trackCollections(), diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 9ab30932bb1..b11d0dda32f 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -878,18 +878,15 @@ SeratoFeature::SeratoFeature( LIBRARYTABLE_TRACKNUMBER, TRACKLOCATIONSTABLE_LOCATION, LIBRARYTABLE_COMMENT, - LIBRARYTABLE_DURATION, - LIBRARYTABLE_BITRATE, - LIBRARYTABLE_BPM, - LIBRARYTABLE_KEY}; + LIBRARYTABLE_GROUPING}; m_trackSource = QSharedPointer( new BaseTrackCache(m_pTrackCollection, kSeratoLibraryTable, std::move(idColumn), std::move(columns), + std::move(searchColumns), false)); - m_trackSource->setSearchColumns(std::move(searchColumns)); m_pSeratoPlaylistModel = new SeratoPlaylistModel(this, pLibrary->trackCollections(), m_trackSource); m_title = tr("Serato"); diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index d71ba0f3e69..963229c2d08 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -97,8 +97,8 @@ TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) tableName, std::move(idColumn), std::move(columns), + std::move(searchColumns), false)); - m_trackSource->setSearchColumns(std::move(searchColumns)); m_isActivated = false; m_pTraktorTableModel = new TraktorTrackModel(this, pLibrary->trackCollections(), m_trackSource); From 734d4107bed805bec8e577bd544e2b8fc7ecd1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 22 Jan 2023 16:28:52 +0100 Subject: [PATCH 13/75] Use QStringLiteral for Library columns --- src/library/banshee/bansheeplaylistmodel.cpp | 66 +++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index edd1905b27c..38a5bc87248 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -40,6 +40,28 @@ namespace { QAtomicInt sTableNumber; +const QString kTrackId = QStringLiteral(CLM_TRACK_ID); +const QString kViewOrder = QStringLiteral(CLM_VIEW_ORDER); +const QString KArtist = QStringLiteral(CLM_ARTIST); +const QString KTitel = QStringLiteral(CLM_TITLE); +const QString kDuration = QStringLiteral(CLM_DURATION); +const QString kUri = QStringLiteral(CLM_URI); +const QString kAlbum = QStringLiteral(CLM_ALBUM); +const QString kAlbumArtist = QStringLiteral(CLM_ALBUM_ARTIST); +const QString kYear = QStringLiteral(CLM_YEAR); +const QString kRating = QStringLiteral(CLM_RATING); +const QString kGenre = QStringLiteral(CLM_GENRE); +const QString kGrouping = QStringLiteral(CLM_GROUPING); +const QString kTracknumber = QStringLiteral(CLM_TRACKNUMBER); +const QString kDateadded = QStringLiteral(CLM_DATEADDED); +const QString kBpm = QStringLiteral(CLM_BPM); +const QString kBitrate = QStringLiteral(CLM_BITRATE); +const QString kComment = QStringLiteral(CLM_COMMENT); +const QString kPlaycount = QStringLiteral(CLM_PLAYCOUNT); +const QString kComposer = QStringLiteral(CLM_COMPOSER); +const QString kPreview = QStringLiteral(CLM_PREVIEW); +const QString kCrate = QStringLiteral(CLM_CRATE); + } // namespace BansheePlaylistModel::BansheePlaylistModel(QObject* pParent, TrackCollectionManager* pTrackCollectionManager, BansheeDbConnection* pConnection) @@ -188,32 +210,32 @@ void BansheePlaylistModel::setTableModel(int playlistId) { } } - const QString idColumn = CLM_TRACK_ID; + const QString idColumn = kTrackId; QStringList tableColumns = { - CLM_TRACK_ID, - CLM_VIEW_ORDER, - CLM_PREVIEW}; // 3 + kTrackId, + kViewOrder, + kPreview}; // 3 QStringList trackSourceColumns = { - CLM_TRACK_ID, // 0 - CLM_ARTIST, - CLM_TITLE, - CLM_DURATION, - CLM_URI, - CLM_ALBUM, - CLM_ALBUM_ARTIST, - CLM_YEAR, - CLM_RATING, - CLM_GENRE, - CLM_GROUPING, - CLM_TRACKNUMBER, - CLM_DATEADDED, - CLM_BPM, - CLM_BITRATE, - CLM_COMMENT, - CLM_PLAYCOUNT, - CLM_COMPOSER}; + kTrackId, // 0 + KArtist, + KTitel, + kDuration, + kUri, + kAlbum, + kAlbumArtist, + kYear, + kRating, + kGenre, + kGrouping, + kTracknumber, + kDateadded, + kBpm, + kBitrate, + kComment, + kPlaycount, + kComposer}; QStringList searchColumns = { KArtist, kAlbum, From 6cfdc9c69d379bfb3460d3846dc25df408e9a737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 24 Jan 2023 23:13:30 +0100 Subject: [PATCH 14/75] Use std::unique_ptr when creating the library tree --- src/library/autodj/autodjfeature.cpp | 7 ++- src/library/baseplaylistfeature.cpp | 12 ++--- src/library/browse/browsefeature.cpp | 41 ++++++++--------- src/library/crate/cratefeature.cpp | 8 ++-- src/library/rekordbox/rekordboxfeature.cpp | 51 +++++++++++----------- src/library/serato/seratofeature.cpp | 32 +++++++------- src/library/treeitem.cpp | 30 ++++--------- src/library/treeitem.h | 8 +--- src/library/treeitemmodel.cpp | 9 ++-- src/library/treeitemmodel.h | 5 ++- 10 files changed, 90 insertions(+), 113 deletions(-) diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index be253659871..d500416cd53 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -216,11 +216,10 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { } // No child item for crate found // -> Create and append a new child item for this crate - QList rows; - rows.append(new TreeItem(crate.getName(), crate.getId().toVariant())); + std::vector> rows; + rows.push_back(std::make_unique(crate.getName(), crate.getId().toVariant())); QModelIndex parentIndex = m_childModel.index(0, 0); - m_childModel.insertTreeItemRows(rows, m_crateList.length(), parentIndex); - DEBUG_ASSERT(rows.isEmpty()); // ownership passed to m_childModel + m_childModel.insertTreeItemRows(std::move(rows), m_crateList.length(), parentIndex); m_crateList.append(crate); } else { // Crate does not exist or is not a source for AutoDJ diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index 5acecd7cabe..e547a63feea 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -618,7 +618,7 @@ void BasePlaylistFeature::htmlLinkClicked(const QUrl& link) { * This method queries the database and does dynamic insertion */ QModelIndex BasePlaylistFeature::constructChildModel(int selected_id) { - QList data_list; + std::vector> data_list; int selected_row = -1; int row = 0; @@ -633,17 +633,17 @@ QModelIndex BasePlaylistFeature::constructChildModel(int selected_id) { } // Create the TreeItem whose parent is the invisible root item - TreeItem* item = new TreeItem(playlistLabel, playlistId); - item->setBold(m_playlistsSelectedTrackIsIn.contains(playlistId)); + std::unique_ptr pItem = std::make_unique(playlistLabel, playlistId); + pItem->setBold(m_playlistsSelectedTrackIsIn.contains(playlistId)); - decorateChild(item, playlistId); - data_list.append(item); + decorateChild(pItem.get(), playlistId); + data_list.push_back(std::move(pItem)); ++row; } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(data_list, 0); + m_childModel.insertTreeItemRows(std::move(data_list), 0); if (selected_row == -1) { return QModelIndex(); } diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 46f26087ce2..3baa45bd910 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -151,11 +151,9 @@ void BrowseFeature::slotAddQuickLink() { QString name = extractNameFromPath(spath); QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); - auto pNewChild = std::make_unique(name, vpath); - QList rows; - rows.append(pNewChild.get()); - pNewChild.release(); - m_childModel.insertTreeItemRows(rows, m_pQuickLinkItem->childRows(), parent); + std::vector> rows; + rows.push_back(std::make_unique(name, vpath)); + m_childModel.insertTreeItemRows(std::move(rows), m_pQuickLinkItem->childRows(), parent); m_quickLinkList.append(spath); saveQuickLinks(); @@ -311,8 +309,8 @@ void BrowseFeature::onRightClickChild(const QPoint& globalPos, const QModelIndex namespace { // Get the list of devices (under "Removable Devices" section). -QList getRemovableDevices() { - QList ret; +std::vector> createRemovableDevices() { + std::vector> ret; #if defined(__WINDOWS__) // Repopulate drive list QFileInfoList drives = QDir::drives(); @@ -330,10 +328,9 @@ QList getRemovableDevices() { if (display_path.endsWith("/")) { display_path.chop(1); } - TreeItem* driveLetter = new TreeItem( - display_path, // Displays C: - drive.filePath()); // Displays C:/ - ret << driveLetter; + ret.push_back(std::make_unique( + display_path, // Displays C: + drive.filePath())); // Displays C:/ } #elif defined(__LINUX__) // To get devices on Linux, we look for directories under /media and @@ -351,10 +348,9 @@ QList getRemovableDevices() { // Convert devices into a QList for display. foreach(QFileInfo device, devices) { - TreeItem* folder = new TreeItem( - device.fileName(), - QVariant(device.filePath() + QStringLiteral("/"))); - ret << folder; + ret.push_back(std::make_unique( + device.fileName(), + QVariant(device.filePath() + QStringLiteral("/")))); } #endif return ret; @@ -395,11 +391,11 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { m_childModel.removeRows(0, item->childRows(), index); // List of subfolders or drive letters - QList folders; + std::vector> folders; // If we are on the special device node if (path == DEVICE_NODE) { - folders += getRemovableDevices(); + folders = createRemovableDevices(); } else { // we assume that the path refers to a folder in the file system // populate children @@ -418,17 +414,16 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { // We here create new items for the sidebar models // Once the items are added to the TreeItemModel, // the models takes ownership of them and ensures their deletion - TreeItem* folder = new TreeItem( - one.fileName(), - QVariant(one.absoluteFilePath() + QStringLiteral("/"))); - folders << folder; + folders.push_back(std::make_unique( + one.fileName(), + QVariant(one.absoluteFilePath() + QStringLiteral("/")))); } } // we need to check here if subfolders are found // On Ubuntu 10.04, otherwise, this will draw an icon although the folder // has no subfolders - if (!folders.isEmpty()) { - m_childModel.insertTreeItemRows(folders, 0, index); + if (!folders.empty()) { + m_childModel.insertTreeItemRows(std::move(folders), 0, index); } } diff --git a/src/library/crate/cratefeature.cpp b/src/library/crate/cratefeature.cpp index b2651e0ce73..2a8eec93631 100644 --- a/src/library/crate/cratefeature.cpp +++ b/src/library/crate/cratefeature.cpp @@ -485,7 +485,7 @@ QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { } m_childModel.removeRows(0, pRootItem->childRows()); - QList modelRows; + std::vector> modelRows; modelRows.reserve(m_pTrackCollection->crates().countCrates()); int selectedRow = -1; @@ -493,9 +493,7 @@ QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { m_pTrackCollection->crates().selectCrateSummaries()); CrateSummary crateSummary; while (crateSummaries.populateNext(&crateSummary)) { - auto pTreeItem = newTreeItemForCrateSummary(crateSummary); - modelRows.append(pTreeItem.get()); - pTreeItem.release(); + modelRows.push_back(newTreeItemForCrateSummary(crateSummary)); if (selectedCrateId == crateSummary.getId()) { // save index for selection selectedRow = modelRows.size() - 1; @@ -503,7 +501,7 @@ QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(modelRows, 0); + m_childModel.insertTreeItemRows(std::move(modelRows), 0); // Update rendering of crates depending on the currently selected track slotTrackSelected(m_pSelectedTrack); diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index ac403f97493..813f0dd607c 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -162,6 +162,8 @@ bool dropTable(QSqlDatabase& database, const QString& tableName) { } // This function is executed in a separate thread other than the main thread +// The returned list owns the pointers, but we can't use a unique_ptr because +// the result is passed by a const reference QList findRekordboxDevices() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); @@ -192,10 +194,10 @@ QList findRekordboxDevices() { QList data; data << drive.filePath(); data << IS_RECORDBOX_DEVICE; - TreeItem* foundDevice = new TreeItem( + auto* pFoundDevice = new TreeItem( std::move(displayPath), QVariant(data)); - foundDevices << foundDevice; + foundDevices << pFoundDevice; } } #elif defined(__LINUX__) @@ -223,10 +225,10 @@ QList findRekordboxDevices() { QList data; data << device.filePath(); data << IS_RECORDBOX_DEVICE; - TreeItem* foundDevice = new TreeItem( + auto* pFoundDevice = new TreeItem( device.fileName(), QVariant(data)); - foundDevices << foundDevice; + foundDevices << pFoundDevice; } } #else // __APPLE__ @@ -239,10 +241,10 @@ QList findRekordboxDevices() { QList data; data << device.filePath(); data << IS_RECORDBOX_DEVICE; - auto* foundDevice = new TreeItem( + auto* pFoundDevice = new TreeItem( device.fileName(), QVariant(data)); - foundDevices << foundDevice; + foundDevices << pFoundDevice; } } #endif @@ -1315,14 +1317,14 @@ RekordboxFeature::~RekordboxFeature() { transaction.commit(); } -void RekordboxFeature::bindLibraryWidget(WLibrary* libraryWidget, +void RekordboxFeature::bindLibraryWidget(WLibrary* pLibraryWidget, KeyboardEventFilter* keyboard) { Q_UNUSED(keyboard); - WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget); - edit->setHtml(formatRootViewHtml()); - edit->setOpenLinks(false); - connect(edit, &WLibraryTextBrowser::anchorClicked, this, &RekordboxFeature::htmlLinkClicked); - libraryWidget->registerView("REKORDBOXHOME", edit); + parented_ptr pEdit = make_parented(pLibraryWidget); + pEdit->setHtml(formatRootViewHtml()); + pEdit->setOpenLinks(false); + connect(pEdit, &WLibraryTextBrowser::anchorClicked, this, &RekordboxFeature::htmlLinkClicked); + pLibraryWidget->registerView("REKORDBOXHOME", pEdit); } void RekordboxFeature::htmlLinkClicked(const QUrl& link) { @@ -1461,9 +1463,12 @@ void RekordboxFeature::activateChild(const QModelIndex& index) { } void RekordboxFeature::onRekordboxDevicesFound() { - QList foundDevices = m_devicesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + std::vector> foundDevices; + for (const auto& pDeviceFound : m_devicesFuture.result()) { + foundDevices.emplace_back(pDeviceFound); + } + TreeItem* root = m_childModel.getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); if (foundDevices.size() == 0) { @@ -1490,10 +1495,8 @@ void RekordboxFeature::onRekordboxDevicesFound() { TreeItem* child = root->child(deviceIndex); bool removeChild = true; - for (int foundDeviceIndex = 0; foundDeviceIndex < foundDevices.size(); foundDeviceIndex++) { - TreeItem* deviceFound = foundDevices[foundDeviceIndex]; - - if (deviceFound->getLabel() == child->getLabel()) { + for (const auto& pDeviceFound : foundDevices) { + if (pDeviceFound->getLabel() == child->getLabel()) { removeChild = false; break; } @@ -1507,28 +1510,26 @@ void RekordboxFeature::onRekordboxDevicesFound() { } } - QList childrenToAdd; + std::vector> childrenToAdd; - for (int foundDeviceIndex = 0; foundDeviceIndex < foundDevices.size(); foundDeviceIndex++) { - TreeItem* deviceFound = foundDevices[foundDeviceIndex]; + for (auto&& pDeviceFound : foundDevices) { bool addNewChild = true; - for (int deviceIndex = 0; deviceIndex < root->childRows(); deviceIndex++) { TreeItem* child = root->child(deviceIndex); - if (deviceFound->getLabel() == child->getLabel()) { + if (pDeviceFound->getLabel() == child->getLabel()) { // This device already exists in the TreeModel, don't add or parse is again addNewChild = false; } } if (addNewChild) { - childrenToAdd << deviceFound; + childrenToAdd.push_back(std::move(pDeviceFound)); } } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_childModel.insertTreeItemRows(std::move(childrenToAdd), 0); } } diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index b11d0dda32f..975c68d8d75 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -669,6 +669,8 @@ QString parseDatabase(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dat } // This function is executed in a separate thread other than the main thread +// The returned list owns the pointers, but we can't use a unique_ptr because +// the result is passed by a const reference QList findSeratoDatabases() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); @@ -1062,9 +1064,12 @@ void SeratoFeature::activateChild(const QModelIndex& index) { } void SeratoFeature::onSeratoDatabasesFound() { - QList foundDatabases = m_databasesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + std::vector> foundDatabases; + for (const auto& pDatabaseFound : m_databasesFuture.result()) { + foundDatabases.emplace_back(pDatabaseFound); + } + TreeItem* root = m_childModel.getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); if (foundDatabases.size() == 0) { @@ -1079,44 +1084,37 @@ void SeratoFeature::onSeratoDatabasesFound() { TreeItem* child = root->child(databaseIndex); bool removeChild = true; - for (int foundDatabaseIndex = 0; foundDatabaseIndex < foundDatabases.size(); foundDatabaseIndex++) { - TreeItem* databaseFound = foundDatabases[foundDatabaseIndex]; - - if (databaseFound->getLabel() == child->getLabel()) { + for (const auto& pDatabaseFound : foundDatabases) { + if (pDatabaseFound->getLabel() == child->getLabel()) { removeChild = false; break; } } - if (removeChild) { // Device has since been unmounted, cleanup DB - m_childModel.removeRows(databaseIndex, 1); } } - QList childrenToAdd; + std::vector> childrenToAdd; - for (int foundDatabaseIndex = 0; foundDatabaseIndex < foundDatabases.size(); foundDatabaseIndex++) { - TreeItem* databaseFound = foundDatabases[foundDatabaseIndex]; + for (auto&& pDatabaseFound : foundDatabases) { bool addNewChild = true; - for (int databaseIndex = 0; databaseIndex < root->childRows(); databaseIndex++) { TreeItem* child = root->child(databaseIndex); - - if (databaseFound->getLabel() == child->getLabel()) { + if (pDatabaseFound->getLabel() == child->getLabel()) { // This database already exists in the TreeModel, don't add or parse is again addNewChild = false; + break; } } - if (addNewChild) { - childrenToAdd << databaseFound; + childrenToAdd.push_back(std::move(pDatabaseFound)); } } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_childModel.insertTreeItemRows(std::move(childrenToAdd), 0); } } diff --git a/src/library/treeitem.cpp b/src/library/treeitem.cpp index c7db2a6be4e..b509dc2e18c 100644 --- a/src/library/treeitem.cpp +++ b/src/library/treeitem.cpp @@ -56,16 +56,16 @@ TreeItem* TreeItem::child(int row) const { return m_children[row]; } -void TreeItem::insertChild(int row, TreeItem* pChild) { +void TreeItem::insertChild(int row, std::unique_ptr pChild) { DEBUG_ASSERT(pChild); DEBUG_ASSERT(!pChild->m_pParent); DEBUG_ASSERT(!pChild->m_pFeature || pChild->m_pFeature == m_pFeature); DEBUG_ASSERT(row >= 0); DEBUG_ASSERT(row <= m_children.size()); - m_children.insert(row, pChild); pChild->m_pParent = this; pChild->initFeatureRecursively(m_pFeature); + m_children.insert(row, pChild.release()); // transfer ownership } void TreeItem::initFeatureRecursively(LibraryFeature* pFeature) { @@ -82,34 +82,22 @@ void TreeItem::initFeatureRecursively(LibraryFeature* pFeature) { } } -TreeItem* TreeItem::appendChild( - std::unique_ptr pChild) { - insertChild(m_children.size(), pChild.get()); // transfer ownership - return pChild.release(); -} - TreeItem* TreeItem::appendChild( QString label, QVariant data) { - auto pNewChild = std::make_unique( + std::unique_ptr pNewChild = std::make_unique( std::move(label), std::move(data)); - return appendChild(std::move(pNewChild)); -} - -void TreeItem::removeChild(int row) { - DEBUG_ASSERT(row >= 0); - DEBUG_ASSERT(row < m_children.size()); - delete m_children.takeAt(row); + TreeItem* pRet = pNewChild.get(); + insertChild(m_children.size(), std::move(pNewChild)); + return pRet; } -void TreeItem::insertChildren(int row, QList& children) { +void TreeItem::insertChildren(int row, std::vector>&& children) { DEBUG_ASSERT(row >= 0); DEBUG_ASSERT(row <= m_children.size()); - while (!children.isEmpty()) { - TreeItem* pChild = children.front(); - insertChild(row++, pChild); - children.pop_front(); + for (auto&& pChild : children) { + insertChild(row++, std::move(pChild)); } } diff --git a/src/library/treeitem.h b/src/library/treeitem.h index 92a8b958877..e7adbf44ecb 100644 --- a/src/library/treeitem.h +++ b/src/library/treeitem.h @@ -83,17 +83,13 @@ class TreeItem final { return m_children; } - // single child items - TreeItem* appendChild( - std::unique_ptr pChild); TreeItem* appendChild( QString label, QVariant data = QVariant()); - void removeChild(int row); // multiple child items // take ownership of children items - void insertChildren(int row, QList& children); + void insertChildren(int row, std::vector>&& children); void removeChildren(int row, int count); @@ -135,7 +131,7 @@ class TreeItem final { QString label = QString(), QVariant data = QVariant()); - void insertChild(int row, TreeItem* pChild); + void insertChild(int row, std::unique_ptr pChild); void initFeatureRecursively(LibraryFeature* pFeature); // The library feature is inherited from the parent. diff --git a/src/library/treeitemmodel.cpp b/src/library/treeitemmodel.cpp index f8a869a01ae..7766a02cf9e 100644 --- a/src/library/treeitemmodel.cpp +++ b/src/library/treeitemmodel.cpp @@ -164,13 +164,13 @@ TreeItem* TreeItemModel::setRootItem(std::unique_ptr pRootItem) { /** * Before you can resize the data model dynamically by using 'insertRows' and 'removeRows' - * make sure you have initialized + * make sure you have initialized. */ void TreeItemModel::insertTreeItemRows( - QList& rows, + std::vector>&& rows, int position, const QModelIndex& parent) { - if (rows.isEmpty()) { + if (rows.empty()) { return; } @@ -178,8 +178,7 @@ void TreeItemModel::insertTreeItemRows( DEBUG_ASSERT(pParentItem != nullptr); beginInsertRows(parent, position, position + rows.size() - 1); - pParentItem->insertChildren(position, rows); - DEBUG_ASSERT(rows.isEmpty()); + pParentItem->insertChildren(position, std::move(rows)); endInsertRows(); } diff --git a/src/library/treeitemmodel.h b/src/library/treeitemmodel.h index 4c17604fa1f..212dbb8623c 100644 --- a/src/library/treeitemmodel.h +++ b/src/library/treeitemmodel.h @@ -30,7 +30,10 @@ class TreeItemModel : public QAbstractItemModel { int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; - void insertTreeItemRows(QList &rows, int position, const QModelIndex& parent = QModelIndex()); + void insertTreeItemRows( + std::vector>&&, + int position, + const QModelIndex& parent = QModelIndex()); TreeItem* setRootItem(std::unique_ptr pRootItem); TreeItem* getRootItem() const { From 3260e9c914fa34b5aa8fd5ae795084151ffe708a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 24 Jan 2023 23:14:40 +0100 Subject: [PATCH 15/75] Reset m_pLastRightClickedItem before removing treeItems. This way it cannot become a dangling pointer --- src/library/browse/browsefeature.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 3baa45bd910..2dcdc46b51f 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -204,6 +204,7 @@ void BrowseFeature::slotRemoveQuickLink() { return; } + m_pLastRightClickedItem = nullptr; QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); m_childModel.removeRow(index, parent); @@ -387,6 +388,7 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { return; } + m_pLastRightClickedItem = nullptr; // Before we populate the subtree, we need to delete old subtrees m_childModel.removeRows(0, item->childRows(), index); From 83973e1a80c9b0cb6c921b3427987778ff6ef4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 24 Jan 2023 23:09:02 +0100 Subject: [PATCH 16/75] Clear LastRightClickIndex when removing tree items. It can become a dangling pointer --- src/library/baseexternallibraryfeature.h | 3 +++ src/library/baseplaylistfeature.cpp | 1 + src/library/crate/cratefeature.cpp | 2 ++ src/library/rekordbox/rekordboxfeature.cpp | 2 ++ src/library/serato/seratofeature.cpp | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index 42333a5b847..9aa436ee814 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -45,6 +45,9 @@ class BaseExternalLibraryFeature : public LibraryFeature { QModelIndex lastRightClickedIndex() const { return m_lastRightClickedIndex; } + void clearLastRightClickedIndex() { + m_lastRightClickedIndex = {}; + }; TrackCollection* const m_pTrackCollection; diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index e547a63feea..bc66aacd107 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -671,6 +671,7 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { * Clears the child model dynamically, but the invisible root item remains */ void BasePlaylistFeature::clearChildModel() { + m_lastRightClickedIndex = {}; m_childModel.removeRows(0, m_childModel.rowCount()); } diff --git a/src/library/crate/cratefeature.cpp b/src/library/crate/cratefeature.cpp index 2a8eec93631..88f1a1989f3 100644 --- a/src/library/crate/cratefeature.cpp +++ b/src/library/crate/cratefeature.cpp @@ -479,6 +479,8 @@ void CrateFeature::slotAutoDjTrackSourceChanged() { QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { qDebug() << "CrateFeature::rebuildChildModel()" << selectedCrateId; + m_lastRightClickedIndex = {}; + TreeItem* pRootItem = m_childModel.getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { return QModelIndex(); diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 813f0dd607c..2750caed198 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1468,6 +1468,8 @@ void RekordboxFeature::onRekordboxDevicesFound() { foundDevices.emplace_back(pDeviceFound); } + clearLastRightClickedIndex(); + TreeItem* root = m_childModel.getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 975c68d8d75..72cf07cd6e3 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -1069,6 +1069,8 @@ void SeratoFeature::onSeratoDatabasesFound() { foundDatabases.emplace_back(pDatabaseFound); } + clearLastRightClickedIndex(); + TreeItem* root = m_childModel.getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); From 01d66679a1a053c5d948282223264ad09a4fd0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 27 Jan 2023 00:57:20 +0100 Subject: [PATCH 17/75] Clean up search columns of the Serato and Rekordbox feature to match the behavior of the native Mixxx library --- src/library/rekordbox/rekordboxfeature.cpp | 7 +------ src/library/serato/seratofeature.cpp | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 2750caed198..b675ffec19a 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1257,15 +1257,10 @@ RekordboxFeature::RekordboxFeature( LIBRARYTABLE_ARTIST, LIBRARYTABLE_TITLE, LIBRARYTABLE_ALBUM, - LIBRARYTABLE_YEAR, LIBRARYTABLE_GENRE, LIBRARYTABLE_TRACKNUMBER, TRACKLOCATIONSTABLE_LOCATION, - LIBRARYTABLE_COMMENT, - LIBRARYTABLE_DURATION, - LIBRARYTABLE_BITRATE, - LIBRARYTABLE_BPM, - LIBRARYTABLE_KEY}; + LIBRARYTABLE_COMMENT}; m_trackSource = QSharedPointer( new BaseTrackCache(m_pTrackCollection, diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 72cf07cd6e3..db8ae097f9a 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -875,9 +875,7 @@ SeratoFeature::SeratoFeature( LIBRARYTABLE_ARTIST, LIBRARYTABLE_TITLE, LIBRARYTABLE_ALBUM, - LIBRARYTABLE_YEAR, LIBRARYTABLE_GENRE, - LIBRARYTABLE_TRACKNUMBER, TRACKLOCATIONSTABLE_LOCATION, LIBRARYTABLE_COMMENT, LIBRARYTABLE_GROUPING}; From 9257b80eb371bc6a66fdccbf9c02737d0ded680d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 27 Jan 2023 07:27:12 +0100 Subject: [PATCH 18/75] remove unused m_searchColumnIndices --- src/library/basetrackcache.cpp | 6 ------ src/library/basetrackcache.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp index 27bedea8b8e..c7469ec95a5 100644 --- a/src/library/basetrackcache.cpp +++ b/src/library/basetrackcache.cpp @@ -32,12 +32,6 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, m_bIndexBuilt(false), m_bIsCaching(isCaching), m_database(pTrackCollection->database()) { - // Convert all the search column names to their field indexes because we use - // them a bunch. - m_searchColumnIndices.resize(m_searchColumns.size()); - for (int i = 0; i < m_searchColumns.size(); ++i) { - m_searchColumnIndices[i] = m_columnCache.fieldIndex(m_searchColumns[i]); - } } BaseTrackCache::~BaseTrackCache() { diff --git a/src/library/basetrackcache.h b/src/library/basetrackcache.h index d99ef43af39..95efbdfca21 100644 --- a/src/library/basetrackcache.h +++ b/src/library/basetrackcache.h @@ -127,7 +127,6 @@ class BaseTrackCache : public QObject { const StringCollator m_collator; QStringList m_searchColumns; - QVector m_searchColumnIndices; // Temporary storage for filterAndSort() From 849215ef73c20f19fde4753e95c0e17c3d54e019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 27 Jan 2023 07:40:54 +0100 Subject: [PATCH 19/75] Remove unused include --- src/library/recording/recordingfeature.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/recording/recordingfeature.h b/src/library/recording/recordingfeature.h index 61b26ad7821..abab936428c 100644 --- a/src/library/recording/recordingfeature.h +++ b/src/library/recording/recordingfeature.h @@ -7,7 +7,6 @@ #include "library/browse/browsetablemodel.h" #include "library/browse/foldertreemodel.h" #include "library/libraryfeature.h" -#include "library/proxytrackmodel.h" class RecordingManager; From e79baef354273c190d073dca28930a1fbe5d28fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 27 Jan 2023 08:05:55 +0100 Subject: [PATCH 20/75] Browsetablemodel: Simplify adding search columns. Not yet enabled. --- src/library/browse/browsetablemodel.cpp | 26 ++++++++++--------------- src/library/browse/browsetablemodel.h | 2 -- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp index db60c3180c1..b33d5fe6712 100644 --- a/src/library/browse/browsetablemodel.cpp +++ b/src/library/browse/browsetablemodel.cpp @@ -54,18 +54,16 @@ BrowseTableModel::BrowseTableModel(QObject* parent, listAppendOrReplaceAt(&headerLabels, COLUMN_FILE_CREATION_TIME, tr("File Created")); listAppendOrReplaceAt(&headerLabels, COLUMN_REPLAYGAIN, tr("ReplayGain")); - addSearchColumn(COLUMN_FILENAME); - addSearchColumn(COLUMN_ARTIST); - addSearchColumn(COLUMN_ALBUM); - addSearchColumn(COLUMN_TITLE); - addSearchColumn(COLUMN_GENRE); - addSearchColumn(COLUMN_COMPOSER); - addSearchColumn(COLUMN_KEY); - addSearchColumn(COLUMN_COMMENT); - addSearchColumn(COLUMN_ALBUMARTIST); - addSearchColumn(COLUMN_GROUPING); - addSearchColumn(COLUMN_FILE_MODIFIED_TIME); - addSearchColumn(COLUMN_FILE_CREATION_TIME); + m_searchColumns = { + COLUMN_FILENAME, + COLUMN_ARTIST, + COLUMN_ALBUM, + COLUMN_TITLE, + COLUMN_GENRE, + COLUMN_COMPOSER, + COLUMN_COMMENT, + COLUMN_ALBUMARTIST, + COLUMN_GROUPING}; setDefaultSort(COLUMN_FILENAME, Qt::AscendingOrder); @@ -182,10 +180,6 @@ const QList& BrowseTableModel::searchColumns() const { return m_searchColumns; } -void BrowseTableModel::addSearchColumn(int index) { - m_searchColumns.push_back(index); -} - void BrowseTableModel::setPath(const MDir& path) { m_current_directory = path; m_pBrowseThread->executePopulation(m_current_directory, this); diff --git a/src/library/browse/browsetablemodel.h b/src/library/browse/browsetablemodel.h index 629e9c05a0e..47c4a121d63 100644 --- a/src/library/browse/browsetablemodel.h +++ b/src/library/browse/browsetablemodel.h @@ -79,8 +79,6 @@ class BrowseTableModel final : public QStandardItemModel, public virtual TrackMo void trackChanged(const QString& group, TrackPointer pNewTrack, TrackPointer pOldTrack); private: - void addSearchColumn(int index); - TrackCollectionManager* const m_pTrackCollectionManager; QList m_searchColumns; From 7d786e18bc47c0c77c3af5b5ecffc3345f3c822d Mon Sep 17 00:00:00 2001 From: holopansel Date: Fri, 27 Jan 2023 10:04:46 +0100 Subject: [PATCH 21/75] merged and changes suggested by swiftboy --- .pre-commit-config.yaml | 2 +- res/controllers/Denon-MC7000-scripts.js | 311 ++++++++++++------------ 2 files changed, 157 insertions(+), 156 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e2afa999df2..0d91d6d89ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -87,7 +87,7 @@ repos: hooks: - id: black files: ^tools/.*$ -- repo: https://gitlab.com/pycqa/flake8 +- repo: https://github.com/pycqa/flake8.git rev: '3.9.2' hooks: - id: flake8 diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 57dbd839c84..312a9eee858 100644 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -284,16 +284,16 @@ MC7000.padModeCue = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = true; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = true; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Hot Cue Mode for (var i = 1; i <= 8; i++) { var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); @@ -308,16 +308,16 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = true; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = true; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // switch off PAD illumination MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; @@ -329,16 +329,16 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = true; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = true; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // switch off PAD illumination MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; @@ -350,16 +350,16 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = true; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = true; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Roll Mode MC7000.setPadColor(deckOffset, MC7000.padColor.rolloff); }; @@ -371,16 +371,16 @@ MC7000.padModeSavedLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = true; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = true; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Saved Loop Mode for (var i = 0; i < 8; i++) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; @@ -395,16 +395,16 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = true; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = true; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Slicer Mode MC7000.setPadColor(deckOffset, MC7000.padColor.sliceron); }; @@ -416,16 +416,16 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = true; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = true; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // switch off PAD illumination MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); }; @@ -434,25 +434,24 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.padModeSampler = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; - var samplerOffset = 0; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = true; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = true; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Sampler Mode var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; for (var i = 1; i <= 8; i++) { - samplerOffset = samplerUnitOffset + i; + var samplerOffset = samplerUnitOffset + i; if (engine.getValue("[Sampler" + samplerOffset + "]", "play")) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { @@ -467,25 +466,24 @@ MC7000.padModeSampler = function(channel, control, value, status, group) { MC7000.padModeVelSamp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; - var samplerOffset = 0; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = true; - MC7000.PADModePitch[deckNumber] = false; + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = true; + MC7000.PADModePitch[deckOffset] = false; // change PAD color when switching to Velocity Sampler Mode var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; for (var i = 1; i <= 8; i++) { - samplerOffset = samplerUnitOffset + i; + var samplerOffset = samplerUnitOffset + i; if (engine.getValue("[Sampler" + samplerOffset+ "]", "play")) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 0) { @@ -504,18 +502,18 @@ MC7000.padModePitch = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.halftoneToPadMap[deckNumber-1] = [4, 5, 6, 7, 0, 1, 2, 3]; - - MC7000.PADModeCue[deckNumber] = false; - MC7000.PADModeCueLoop[deckNumber] = false; - MC7000.PADModeFlip[deckNumber] = false; - MC7000.PADModeRoll[deckNumber] = false; - MC7000.PADModeSavedLoop[deckNumber] = false; - MC7000.PADModeSlicer[deckNumber] = false; - MC7000.PADModeSlicerLoop[deckNumber] = false; - MC7000.PADModeSampler[deckNumber] = false; - MC7000.PADModeVelSamp[deckNumber] = false; - MC7000.PADModePitch[deckNumber] = true; + MC7000.halftoneToPadMap[deckOffset] = [4, 5, 6, 7, 0, 1, 2, 3]; + + MC7000.PADModeCue[deckOffset] = false; + MC7000.PADModeCueLoop[deckOffset] = false; + MC7000.PADModeFlip[deckOffset] = false; + MC7000.PADModeRoll[deckOffset] = false; + MC7000.PADModeSavedLoop[deckOffset] = false; + MC7000.PADModeSlicer[deckOffset] = false; + MC7000.PADModeSlicerLoop[deckOffset] = false; + MC7000.PADModeSampler[deckOffset] = false; + MC7000.PADModeVelSamp[deckOffset] = false; + MC7000.PADModePitch[deckOffset] = true; // switch on initial PAD illumination = hotcue for pitch or if // MC7000.HotcueSelectedGroup selected = pad mode pitchoff color @@ -544,7 +542,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { // - MC7000.PADModeSlicerLoop // activate and clear Hot Cues - if (MC7000.PADModeCue[deckNumber] && engine.getValue(group, "track_loaded") === 1) { + if (MC7000.PADModeCue[deckOffset] && engine.getValue(group, "track_loaded") === 1) { for (i = 1; i <= 8; i++) { if (control === 0x14 + i - 1 && value === 0x7F) { engine.setValue(group, "hotcue_" + i + "_activate", true); @@ -561,7 +559,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueoff); } } - } else if (MC7000.PADModeRoll[deckNumber]) { + } else if (MC7000.PADModeRoll[deckOffset]) { // TODO(all): check for actual beatloop_size and apply back after a PAD Roll i = control - 0x14; if (control === 0x14 + i && value > 0x00) { @@ -571,7 +569,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue(group, "beatlooproll_activate", false); midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.rolloff); } - } else if (MC7000.PADModeSavedLoop[deckNumber]) { + } else if (MC7000.PADModeSavedLoop[deckOffset]) { if (value === 0x00) { return; // don't respond to note off messages } @@ -581,7 +579,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[j] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; midi.sendShortMsg(0x94 + deckOffset, 0x14 + j, activeLED); } - } else if (MC7000.PADModeSlicer[deckNumber]) { + } else if (MC7000.PADModeSlicer[deckOffset]) { if (value > 0) { i = control - 0x14; // unshifted button j = control - 0x1C; // shifted button @@ -605,7 +603,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else { midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.sliceron); } - } else if (MC7000.PADModeSampler[deckNumber]) { + } else if (MC7000.PADModeSampler[deckOffset]) { var samplerOffset = 0; var samplerOffsetJ = 0; for (i = 1; i <= 8; i++) { @@ -637,7 +635,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler if (MC7000.SamplerQty === 16) { - if ((deckNumber - 1) >= 2) { + if ((deckOffset) >= 2) { deckOffset = deckOffset + 2; } } @@ -651,7 +649,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } } - } else if (MC7000.PADModeVelSamp[deckNumber]) { + } else if (MC7000.PADModeVelSamp[deckOffset]) { samplerOffset = 0; samplerOffsetJ = 0; for (i = 1; i <= 8; i++) { @@ -684,7 +682,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); if (MC7000.SamplerQty === 16) { - if ((deckNumber - 1) >= 2) { + if ((deckOffset) >= 2) { deckOffset = deckOffset + 2; } } @@ -698,7 +696,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } } - } else if (MC7000.PADModePitch[deckNumber]) { // TODO TODO play and cue dependency to play and cue button + } else if (MC7000.PADModePitch[deckOffset]) { // TODO TODO play and cue dependency to play and cue button if (engine.getValue(group, "track_loaded") === 1) { for (i = 1; i <= 8; i++) { // intermediate variables @@ -717,7 +715,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else { // hotcue selected and button pressed // TODO: play if play, stop if cue engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop MC7000.setPadColor(deckOffset, MC7000.padColor.pitchoff); - engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckNumber-1][i-1]); + engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckOffset][i-1]); engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.pitchon); // keep color when shift is pressed @@ -739,11 +737,11 @@ MC7000.PadButtons = function(channel, control, value, status, group) { midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); midi.sendShortMsg(0x94 + deckOffset, 0x1C + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed } - } // end else if - } // end for - } //end pad mode if - } //end pad mode pitch -}; //end pad buttons + } + } + } + } +}; MC7000.setPadColor = function(deckOffset, colorValue) { @@ -865,19 +863,19 @@ MC7000.wheelTurn = function(channel, control, value, status, group) { // Needle Search Touch detection MC7000.needleSearchTouch = function(channel, control, value, status, group) { - var deckNumber = script.deckFromGroup(group); + var deckOffset = script.deckFromGroup(group) - 1; if (engine.getValue(group, "play")) { - MC7000.needleSearchTouched[deckNumber] = MC7000.needleSearchPlay && (!!value); + MC7000.needleSearchTouched[deckOffset] = MC7000.needleSearchPlay && (!!value); } else { - MC7000.needleSearchTouched[deckNumber] = !!value; + MC7000.needleSearchTouched[deckOffset] = !!value; } }; // Needle Search Touch while "SHIFT" button is pressed MC7000.needleSearchTouchShift = function(channel, control, value, status, group) { - var deckNumber = script.deckFromGroup(group); - MC7000.needleSearchTouched[deckNumber] = !!value; + var deckOffset = script.deckFromGroup(group) - 1; + MC7000.needleSearchTouched[deckOffset] = !!value; }; // Needle Search Position detection (MSB) @@ -888,8 +886,8 @@ MC7000.needleSearchMSB = function(channel, control, value) { // Needle Search Position detection (MSB + LSB) MC7000.needleSearchStripPosition = function(channel, control, value, status, group) { - var deckNumber = script.deckFromGroup(group); - if (MC7000.needleSearchTouched[deckNumber]) { + var deckOffset = script.deckFromGroup(group) - 1; + if (MC7000.needleSearchTouched[deckOffset]) { var fullValue = (MC7000.needleDropMSB << 7) + value; // move MSB 7 binary digits to the left and add LSB var position = (fullValue / 0x3FFF); // divide by all possible positions to get relative between 0 - 1 engine.setParameter(group, "playposition", position); @@ -992,36 +990,38 @@ MC7000.crossfaderAssign = function(channel, control, value, status, group) { // Assign Spinback length to STOP TIME knob MC7000.stopTime = function(channel, control, value, status, group) { - var deckNumber = script.deckFromGroup(group); + var deckOffset = script.deckFromGroup(group) - 1; // "factor" for engine.brake() and engine.softStart() // this formula produces factors between 31 (min STOP TIME for ca 7 sec back // in track) and 1 (max STOP TIME for ca 18.0 sec back in track) - MC7000.factor[deckNumber] = (1.1 - (value / 127)) * 30 - 2; - MC7000.factor2[deckNumber] = (127.69 - value); + MC7000.factor[deckOffset] = (1.1 - (value / 127)) * 30 - 2; + MC7000.factor2[deckOffset] = (127.69 - value); }; -MC7000.lastpress = 0; + +MC7000.lastpress = [0, 0, 0, 0]; MC7000.play = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } var deckNumber = script.deckFromGroup(group); + var deckOffset = deckNumber - 1; // set a variable to toggle between play and pause, based on current play status - var playToggle = 1 - engine.getValue(group, "play_indicator"); - if (MC7000.factor[deckNumber] === 31) { // factor 31 means stop time knob is at zero position - engine.setValue(group, "play", playToggle); - MC7000.lastpress = 0; + var playToggle = engine.getValue(group, "play"); + if (MC7000.factor[deckOffset] === 31) { // factor 31 means stop time knob is at zero position + engine.setValue(group, "play", !playToggle); + MC7000.lastpress[deckOffset] = 0; } else { - if (!playToggle) { - if (!MC7000.lastpress) { - engine.brake(deckNumber, true, MC7000.factor2[deckNumber]); - MC7000.lastpress = 1; + if (playToggle) { + if (!MC7000.lastpress[deckOffset]) { + engine.brake(deckNumber, true, MC7000.factor2[deckOffset]); + MC7000.lastpress[deckOffset] = 1; } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckNumber]); - MC7000.lastpress = 0; + engine.softStart(deckNumber, true, MC7000.factor2[deckOffset]); + MC7000.lastpress[deckOffset] = 0; } } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckNumber]); - MC7000.lastpress = 0; + engine.softStart(deckNumber, true, MC7000.factor2[deckOffset]); + MC7000.lastpress[deckOffset] = 0; } } }; @@ -1029,10 +1029,11 @@ MC7000.play = function(channel, control, value, status, group) { // Use SHIFT + CENSOR button as Spinback with STOP TIME adjusted length MC7000.reverse = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); + var deckOffset = deckNumber - 1; if (value > 0) { // while the button is pressed spin back // start at a rate of -10 and decrease by "MC7000.factor" - engine.brake(deckNumber, true, MC7000.factor[deckNumber], -10); + engine.brake(deckNumber, true, MC7000.factor[deckOffset], -10); } else { if (engine.getValue(group, "slip_enabled")) { engine.brake(deckNumber, false); // disable brake effect @@ -1042,7 +1043,7 @@ MC7000.reverse = function(channel, control, value, status, group) { engine.setValue(group, "slip_enabled", true); }, true); } else { - engine.softStart(deckNumber, true, MC7000.factor[deckNumber]); + engine.softStart(deckNumber, true, MC7000.factor[deckOffset]); } } }; @@ -1072,13 +1073,13 @@ MC7000.censor = function(channel, control, value, status, group) { // Param Button for Pitch Play to increase or decrease pitch, Star rating otherwise MC7000.StarsDown = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - //var deckOffset = deckNumber - 1; + var deckOffset = deckNumber - 1; if (value === 0x00) { //return; // don't respond to note off messages } else { - if (MC7000.PADModePitch[deckNumber]) { + if (MC7000.PADModePitch[deckOffset]) { for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckNumber-1][i] = MC7000.halftoneToPadMap[deckNumber-1][i] - 8; // pitch down + MC7000.halftoneToPadMap[deckOffset][i] = MC7000.halftoneToPadMap[deckOffset][i] - 8; // pitch down } } else { engine.setValue(group, "stars_down", true); // stars down @@ -1088,13 +1089,13 @@ MC7000.StarsDown = function(channel, control, value, status, group) { MC7000.StarsUp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - //var deckOffset = deckNumber - 1; + var deckOffset = deckNumber - 1; if (value === 0x00) { //return; // don't respond to note off messages } else { - if (MC7000.PADModePitch[deckNumber]) { + if (MC7000.PADModePitch[deckOffset]) { for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckNumber-1][i] = MC7000.halftoneToPadMap[deckNumber-1][i] + 8; // pitch up + MC7000.halftoneToPadMap[deckOffset][i] = MC7000.halftoneToPadMap[deckOffset][i] + 8; // pitch up } } else { engine.setValue(group, "stars_up", true); // stars up @@ -1182,7 +1183,7 @@ MC7000.TrackPositionLEDs = function(value, group) { if (!MC7000.experimental) { return; } - if (MC7000.PADModeSlicer[deckNumber]) { + if (MC7000.PADModeSlicer[deckOffset]) { // only send new LED status when beatCountLED really changes if (MC7000.prevPadLED[deckOffset] !== beatCountLED) { // first set all LEDs to default color incl shifted @@ -1209,7 +1210,7 @@ MC7000.TrackPositionLEDs = function(value, group) { MC7000.HotCueLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; - if (MC7000.PADModeCue[deckNumber]) { + if (MC7000.PADModeCue[deckOffset]) { for (var i = 1; i <= 8; i++) { if (value === 1) { if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { @@ -1277,7 +1278,7 @@ MC7000.VelSampLED = function() { MC7000.PitchLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckOffset = deckNumber - 1; - if (MC7000.PADModePitch[deckNumber]) { + if (MC7000.PADModePitch[deckOffset]) { for (var i = 0; i < 8; i++) { if (engine.getValue("[Channel"+deckNumber+"]", "play") === 0) { // stopped if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { // hotcue selected From 04df1ac30df343a341c484f52949c1743ab17323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 29 Jan 2023 02:03:24 +0100 Subject: [PATCH 22/75] Move Serato metadata export into a separate function called after the metadata has been successfully read. This fixes a DEBUG_ASSERT failing when the track file is missing. Fixes #11225 --- src/track/track.cpp | 81 ++++++++++++++++++++++----------------------- src/track/track.h | 2 ++ 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/track/track.cpp b/src/track/track.cpp index fdd07c6edf5..9f6c8b7c305 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -1373,6 +1373,42 @@ quint16 Track::getCoverHash() const { return m_record.getCoverInfo().hash; } +void Track::exportSeratoMetadata() { + const auto streamInfo = m_record.getStreamInfoFromSource(); + VERIFY_OR_DEBUG_ASSERT(streamInfo && + streamInfo->getSignalInfo().isValid() && + streamInfo->getDuration() > mixxx::Duration::empty()) { + kLogger.warning() << "Cannot write Serato metadata because signal " + "info and/or duration is not available:" + << getLocation(); + return; + } + const mixxx::audio::SampleRate sampleRate = + streamInfo->getSignalInfo().getSampleRate(); + mixxx::SeratoTags* seratoTags = + m_record.refMetadata().refTrackInfo().ptrSeratoTags(); + DEBUG_ASSERT(seratoTags); + if (seratoTags->status() == mixxx::SeratoTags::ParserStatus::Failed) { + kLogger.warning() + << "Refusing to overwrite Serato metadata that failed to parse:" + << getLocation(); + } else { + seratoTags->setTrackColor(getColor()); + seratoTags->setBpmLocked(isBpmLocked()); + QList cueInfos; + for (const CuePointer& pCue : qAsConst(m_cuePoints)) { + cueInfos.append(pCue->getCueInfo(sampleRate)); + } + const double timingOffset = mixxx::SeratoTags::guessTimingOffsetMillis( + getLocation(), streamInfo->getSignalInfo()); + seratoTags->setCueInfos(cueInfos, timingOffset); + seratoTags->setBeats(m_pBeats, + streamInfo->getSignalInfo(), + streamInfo->getDuration(), + timingOffset); + } +} + ExportTrackMetadataResult Track::exportMetadata( mixxx::MetadataSourcePointer pMetadataSource, UserSettingsPointer pConfig) { @@ -1403,47 +1439,6 @@ ExportTrackMetadataResult Track::exportMetadata( return ExportTrackMetadataResult::Skipped; } - if (pConfig->getValue(kConfigKeySeratoMetadataExport)) { - const auto streamInfo = m_record.getStreamInfoFromSource(); - VERIFY_OR_DEBUG_ASSERT(streamInfo && - streamInfo->getSignalInfo().isValid() && - streamInfo->getDuration() > mixxx::Duration::empty()) { - kLogger.warning() << "Cannot write Serato metadata because signal " - "info and/or duration is not available:" - << getLocation(); - return ExportTrackMetadataResult::Skipped; - } - - const mixxx::audio::SampleRate sampleRate = - streamInfo->getSignalInfo().getSampleRate(); - - mixxx::SeratoTags* seratoTags = m_record.refMetadata().refTrackInfo().ptrSeratoTags(); - DEBUG_ASSERT(seratoTags); - - if (seratoTags->status() == mixxx::SeratoTags::ParserStatus::Failed) { - kLogger.warning() - << "Refusing to overwrite Serato metadata that failed to parse:" - << getLocation(); - } else { - seratoTags->setTrackColor(getColor()); - seratoTags->setBpmLocked(isBpmLocked()); - - QList cueInfos; - for (const CuePointer& pCue : qAsConst(m_cuePoints)) { - cueInfos.append(pCue->getCueInfo(sampleRate)); - } - - const double timingOffset = mixxx::SeratoTags::guessTimingOffsetMillis( - getLocation(), streamInfo->getSignalInfo()); - seratoTags->setCueInfos(cueInfos, timingOffset); - - seratoTags->setBeats(m_pBeats, - streamInfo->getSignalInfo(), - streamInfo->getDuration(), - timingOffset); - } - } - // Check if the metadata has actually been modified. Otherwise // we don't need to write it back. Exporting unmodified metadata // would needlessly update the file's time stamp and should be @@ -1466,6 +1461,10 @@ ExportTrackMetadataResult Track::exportMetadata( // from file tags cannot be filled during a database migration. m_record.mergeImportedMetadata(importedFromFile); + if (pConfig->getValue(kConfigKeySeratoMetadataExport)) { + exportSeratoMetadata(); + } + // Prepare export by cloning and normalizing the metadata normalizedFromRecord = m_record.getMetadata(); normalizedFromRecord.normalizeBeforeExport(); diff --git a/src/track/track.h b/src/track/track.h index 6f9e1d8e7ef..11ca0b1a9bf 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -450,6 +450,8 @@ class Track : public QObject { }; double getDuration(DurationRounding rounding) const; + void exportSeratoMetadata(); + ExportTrackMetadataResult exportMetadata( mixxx::MetadataSourcePointer pMetadataSource, UserSettingsPointer pConfig); From fecfc149552b6c6be7f8e2578e19e7e0b6059486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 29 Jan 2023 20:12:31 +0100 Subject: [PATCH 23/75] make future result const before iteration --- src/library/basetrackcache.cpp | 4 +- src/library/basetrackcache.h | 2 - src/library/rekordbox/rekordboxfeature.cpp | 3 +- src/library/searchqueryparser.cpp | 48 ++-- src/library/searchqueryparser.h | 9 +- src/library/serato/seratofeature.cpp | 3 +- src/test/searchqueryparsertest.cpp | 254 +++++++-------------- 7 files changed, 121 insertions(+), 202 deletions(-) diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp index c7469ec95a5..c2d44106c1c 100644 --- a/src/library/basetrackcache.cpp +++ b/src/library/basetrackcache.cpp @@ -27,8 +27,7 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, m_columnCount(columns.size()), m_columnsJoined(columns.join(",")), m_columnCache(std::move(columns)), - m_pQueryParser(new SearchQueryParser(pTrackCollection)), - m_searchColumns(std::move(searchColumns)), + m_pQueryParser(new SearchQueryParser(pTrackCollection, std::move(searchColumns))), m_bIndexBuilt(false), m_bIsCaching(isCaching), m_database(pTrackCollection->database()) { @@ -470,7 +469,6 @@ void BaseTrackCache::filterAndSort(const QSet& trackIds, const std::unique_ptr pQuery = m_pQueryParser->parseQuery( searchQuery, - m_searchColumns, queryFragments.join(" AND ")); QString filter = pQuery->toSql(); diff --git a/src/library/basetrackcache.h b/src/library/basetrackcache.h index 95efbdfca21..43d21a34827 100644 --- a/src/library/basetrackcache.h +++ b/src/library/basetrackcache.h @@ -126,8 +126,6 @@ class BaseTrackCache : public QObject { const StringCollator m_collator; - QStringList m_searchColumns; - // Temporary storage for filterAndSort() QVector m_trackOrder; diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index b675ffec19a..6f9e596cd8b 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1459,7 +1459,8 @@ void RekordboxFeature::activateChild(const QModelIndex& index) { void RekordboxFeature::onRekordboxDevicesFound() { std::vector> foundDevices; - for (const auto& pDeviceFound : m_devicesFuture.result()) { + const QList result = m_devicesFuture.result(); + for (const auto& pDeviceFound : result) { foundDevices.emplace_back(pDeviceFound); } diff --git a/src/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 85352b3ad3f..3873bc60d81 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -7,8 +7,11 @@ constexpr char kNegatePrefix[] = "-"; constexpr char kFuzzyPrefix[] = "~"; -SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection) - : m_pTrackCollection(pTrackCollection) { +SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection, QStringList searchColumns) + : m_pTrackCollection(pTrackCollection), + m_searchCrates(false) { + setSearchColumns(std::move(searchColumns)); + m_textFilters << "artist" << "album_artist" << "album" @@ -31,7 +34,6 @@ SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection) << "dateadded" << "datetime_added" << "date_added"; - m_ignoredColumns << "crate"; m_fieldToSqlColumns["artist"] << "artist" << "album_artist"; m_fieldToSqlColumns["album_artist"] << "album_artist"; @@ -66,6 +68,19 @@ SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection) SearchQueryParser::~SearchQueryParser() { } +void SearchQueryParser::setSearchColumns(QStringList searchColumns) { + m_queryColumns = std::move(searchColumns); + + // we need to create a filtered columns list that are handled differently + for (int i = 0; i < m_queryColumns.size(); ++i) { + if (m_queryColumns[i] == "crate") { + m_searchCrates = true; + m_queryColumns.removeAt(i); + break; + } + } +} + QString SearchQueryParser::getTextArgument(QString argument, QStringList* tokens) const { // If the argument is empty, assume the user placed a space after an @@ -116,20 +131,7 @@ QString SearchQueryParser::getTextArgument(QString argument, } void SearchQueryParser::parseTokens(QStringList tokens, - QStringList searchColumns, AndNode* pQuery) const { - // we need to create a filtered columns list that are handled differently - auto queryColumns = QStringList(); - queryColumns.reserve(searchColumns.count()); - - for (const auto& column: qAsConst(searchColumns)) { - if (m_ignoredColumns.contains(column)) { - continue; - } - queryColumns << column; - } - - while (tokens.size() > 0) { QString token = tokens.takeFirst().trimmed(); if (token.length() == 0) { @@ -224,18 +226,18 @@ void SearchQueryParser::parseTokens(QStringList tokens, // For untagged strings we search the track fields as well // as the crate names the track is in. This allows the user // to use crates like tags - if (searchColumns.contains("crate")) { + if (m_searchCrates) { std::unique_ptr gNode = std::make_unique(); gNode->addNode(std::make_unique( &m_pTrackCollection->crates(), argument)); gNode->addNode(std::make_unique( - m_pTrackCollection->database(), queryColumns, argument)); + m_pTrackCollection->database(), m_queryColumns, argument)); pNode = std::move(gNode); } else { pNode = std::make_unique( - m_pTrackCollection->database(), queryColumns, argument); + m_pTrackCollection->database(), m_queryColumns, argument); } } } @@ -248,9 +250,9 @@ void SearchQueryParser::parseTokens(QStringList tokens, } } -std::unique_ptr SearchQueryParser::parseQuery(const QString& query, - const QStringList& searchColumns, - const QString& extraFilter) const { +std::unique_ptr SearchQueryParser::parseQuery( + const QString& query, + const QString& extraFilter) const { auto pQuery(std::make_unique()); if (!extraFilter.isEmpty()) { @@ -259,7 +261,7 @@ std::unique_ptr SearchQueryParser::parseQuery(const QString& query, if (!query.isEmpty()) { QStringList tokens = query.split(" "); - parseTokens(tokens, searchColumns, pQuery.get()); + parseTokens(tokens, pQuery.get()); } return pQuery; diff --git a/src/library/searchqueryparser.h b/src/library/searchqueryparser.h index 9878149c0a7..848a750a802 100644 --- a/src/library/searchqueryparser.h +++ b/src/library/searchqueryparser.h @@ -10,29 +10,30 @@ class SearchQueryParser { public: - explicit SearchQueryParser(TrackCollection* pTrackCollection); + explicit SearchQueryParser(TrackCollection* pTrackCollection, QStringList searchColumns); virtual ~SearchQueryParser(); + void setSearchColumns(QStringList searchColumns); + std::unique_ptr parseQuery( const QString& query, - const QStringList& searchColumns, const QString& extraFilter) const; private: void parseTokens(QStringList tokens, - QStringList searchColumns, AndNode* pQuery) const; QString getTextArgument(QString argument, QStringList* tokens) const; TrackCollection* m_pTrackCollection; + QStringList m_queryColumns; + bool m_searchCrates; QStringList m_textFilters; QStringList m_numericFilters; QStringList m_specialFilters; - QStringList m_ignoredColumns; QStringList m_allFilters; QHash m_fieldToSqlColumns; diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index db8ae097f9a..95c16e305c3 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -1063,7 +1063,8 @@ void SeratoFeature::activateChild(const QModelIndex& index) { void SeratoFeature::onSeratoDatabasesFound() { std::vector> foundDatabases; - for (const auto& pDatabaseFound : m_databasesFuture.result()) { + const QList result = m_databasesFuture.result(); + for (const auto& pDatabaseFound : result) { foundDatabases.emplace_back(pDatabaseFound); } diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index ae333c6a67d..49626b0877a 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -21,7 +21,7 @@ TrackPointer newTestTrack(int sampleRate) { class SearchQueryParserTest : public LibraryTest { protected: SearchQueryParserTest() - : m_parser(internalCollection()) { + : m_parser(internalCollection(), QStringList()) { } virtual ~SearchQueryParserTest() { @@ -43,7 +43,7 @@ class SearchQueryParserTest : public LibraryTest { TEST_F(SearchQueryParserTest, EmptySearch) { auto pQuery( - m_parser.parseQuery("", QStringList(), "")); + m_parser.parseQuery("", QString())); // An empty query matches all tracks. TrackPointer pTrack(Track::newTemporary()); @@ -54,11 +54,9 @@ TEST_F(SearchQueryParserTest, EmptySearch) { } TEST_F(SearchQueryParserTest, OneTermOneColumn) { - QStringList searchColumns; - searchColumns << "artist"; - + m_parser.setSearchColumns({"artist"}); auto pQuery( - m_parser.parseQuery("asdf", searchColumns, "")); + m_parser.parseQuery("asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("testASDFtest"); @@ -72,12 +70,9 @@ TEST_F(SearchQueryParserTest, OneTermOneColumn) { } TEST_F(SearchQueryParserTest, OneTermMultipleColumns) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("asdf", searchColumns, "")); + m_parser.parseQuery("asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("testASDFtest"); @@ -91,12 +86,9 @@ TEST_F(SearchQueryParserTest, OneTermMultipleColumns) { } TEST_F(SearchQueryParserTest, OneTermMultipleColumnsNegation) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("-asdf", searchColumns, "")); + m_parser.parseQuery("-asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("testASDFtest"); @@ -110,11 +102,9 @@ TEST_F(SearchQueryParserTest, OneTermMultipleColumnsNegation) { } TEST_F(SearchQueryParserTest, MultipleTermsOneColumn) { - QStringList searchColumns; - searchColumns << "artist"; - + m_parser.setSearchColumns({"artist"}); auto pQuery( - m_parser.parseQuery("asdf zxcv", searchColumns, "")); + m_parser.parseQuery("asdf zxcv", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("test zXcV test"); @@ -128,12 +118,9 @@ TEST_F(SearchQueryParserTest, MultipleTermsOneColumn) { } TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumns) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("asdf zxcv", searchColumns, "")); + m_parser.parseQuery("asdf zxcv", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("asdf zxcv"); @@ -153,12 +140,9 @@ TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumns) { } TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumnsNegation) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("asdf -zxcv", searchColumns, "")); + m_parser.parseQuery("asdf -zxcv", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setTitle("asdf zxcv"); @@ -179,12 +163,9 @@ TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumnsNegation) { } TEST_F(SearchQueryParserTest, TextFilter) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment:asdf", searchColumns, "")); + m_parser.parseQuery("comment:asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -198,13 +179,10 @@ TEST_F(SearchQueryParserTest, TextFilter) { } TEST_F(SearchQueryParserTest, TextFilterEmpty) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); // An empty argument should pass everything. auto pQuery( - m_parser.parseQuery("comment:", searchColumns, "")); + m_parser.parseQuery("comment:", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setComment("test ASDF test"); @@ -216,12 +194,9 @@ TEST_F(SearchQueryParserTest, TextFilterEmpty) { } TEST_F(SearchQueryParserTest, TextFilterQuote) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment:\"asdf zxcv\"", searchColumns, "")); + m_parser.parseQuery("comment:\"asdf zxcv\"", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf zxcv"); @@ -235,12 +210,9 @@ TEST_F(SearchQueryParserTest, TextFilterQuote) { } TEST_F(SearchQueryParserTest, TextFilterQuote_NoEndQuoteTakesWholeQuery) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment:\"asdf zxcv qwer", searchColumns, "")); + m_parser.parseQuery("comment:\"asdf zxcv qwer", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf zxcv qwer"); @@ -254,12 +226,9 @@ TEST_F(SearchQueryParserTest, TextFilterQuote_NoEndQuoteTakesWholeQuery) { } TEST_F(SearchQueryParserTest, TextFilterAllowsSpace) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment: asdf", searchColumns, "")); + m_parser.parseQuery("comment: asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -273,12 +242,9 @@ TEST_F(SearchQueryParserTest, TextFilterAllowsSpace) { } TEST_F(SearchQueryParserTest, TextFilterQuotes) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment:\"asdf ewe\"", searchColumns, "")); + m_parser.parseQuery("comment:\"asdf ewe\"", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -292,12 +258,10 @@ TEST_F(SearchQueryParserTest, TextFilterQuotes) { } TEST_F(SearchQueryParserTest, TextFilterDecoration) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - - auto pQuery( - m_parser.parseQuery(QString::fromUtf8("comment:\"asdf\xC2\xB0 ewe\""), searchColumns, "")); // with Ëš + m_parser.setSearchColumns({"artist", "album"}); + auto pQuery(m_parser.parseQuery( + QString::fromUtf8("comment:\"asdf\xC2\xB0 ewe\""), + QString())); // with Ëš TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -316,12 +280,9 @@ TEST_F(SearchQueryParserTest, TextFilterDecoration) { } TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("comment:\"asdf \"", searchColumns, "")); + m_parser.parseQuery("comment:\"asdf \"", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -335,7 +296,7 @@ TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) { // We allow to search for two consequitve spaces auto pQuery2( - m_parser.parseQuery("comment:\" \"", searchColumns, "")); + m_parser.parseQuery("comment:\" \"", QString())); EXPECT_FALSE(pQuery2->match(pTrack)); @@ -345,12 +306,9 @@ TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) { } TEST_F(SearchQueryParserTest, TextFilterNegation) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("-comment: asdf", searchColumns, "")); + m_parser.parseQuery("-comment: asdf", QString())); TrackPointer pTrack(Track::newTemporary()); pTrack->setArtist("asdf"); @@ -364,12 +322,9 @@ TEST_F(SearchQueryParserTest, TextFilterNegation) { } TEST_F(SearchQueryParserTest, NumericFilter) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("bpm:127.12", searchColumns, "")); + m_parser.parseQuery("bpm:127.12", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(127); @@ -383,12 +338,9 @@ TEST_F(SearchQueryParserTest, NumericFilter) { } TEST_F(SearchQueryParserTest, NumericFilterEmpty) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("bpm:", searchColumns, "")); + m_parser.parseQuery("bpm:", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(127); @@ -400,12 +352,9 @@ TEST_F(SearchQueryParserTest, NumericFilterEmpty) { } TEST_F(SearchQueryParserTest, NumericFilterNegation) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("-bpm:127.12", searchColumns, "")); + m_parser.parseQuery("-bpm:127.12", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(127); @@ -419,12 +368,9 @@ TEST_F(SearchQueryParserTest, NumericFilterNegation) { } TEST_F(SearchQueryParserTest, NumericFilterAllowsSpace) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("bpm: 127.12", searchColumns, "")); + m_parser.parseQuery("bpm: 127.12", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(127); @@ -438,12 +384,9 @@ TEST_F(SearchQueryParserTest, NumericFilterAllowsSpace) { } TEST_F(SearchQueryParserTest, NumericFilterOperators) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("bpm:>127.12", searchColumns, "")); + m_parser.parseQuery("bpm:>127.12", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(127.12); @@ -454,8 +397,7 @@ TEST_F(SearchQueryParserTest, NumericFilterOperators) { qPrintable(QString("bpm > 127.12")), qPrintable(pQuery->toSql())); - - pQuery = m_parser.parseQuery("bpm:>=127.12", searchColumns, ""); + pQuery = m_parser.parseQuery("bpm:>=127.12", QString()); pTrack->trySetBpm(127.11); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->trySetBpm(127.12); @@ -464,7 +406,7 @@ TEST_F(SearchQueryParserTest, NumericFilterOperators) { qPrintable(QString("bpm >= 127.12")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("bpm:<127.12", searchColumns, ""); + pQuery = m_parser.parseQuery("bpm:<127.12", QString()); pTrack->trySetBpm(127.12); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->trySetBpm(127.11); @@ -473,7 +415,7 @@ TEST_F(SearchQueryParserTest, NumericFilterOperators) { qPrintable(QString("bpm < 127.12")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("bpm:<=127.12", searchColumns, ""); + pQuery = m_parser.parseQuery("bpm:<=127.12", QString()); pTrack->trySetBpm(127.13); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->trySetBpm(127.12); @@ -484,12 +426,9 @@ TEST_F(SearchQueryParserTest, NumericFilterOperators) { } TEST_F(SearchQueryParserTest, NumericRangeFilter) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("bpm:127.12-129", searchColumns, "")); + m_parser.parseQuery("bpm:127.12-129", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(125); @@ -505,13 +444,9 @@ TEST_F(SearchQueryParserTest, NumericRangeFilter) { } TEST_F(SearchQueryParserTest, MultipleFilters) { - QStringList searchColumns; - searchColumns << "artist" - << "title"; - + m_parser.setSearchColumns({"artist", "title"}); auto pQuery( - m_parser.parseQuery("bpm:127.12-129 artist:\"com truise\" Colorvision", - searchColumns, "")); + m_parser.parseQuery("bpm:127.12-129 artist:\"com truise\" Colorvision", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->trySetBpm(128); @@ -529,11 +464,9 @@ TEST_F(SearchQueryParserTest, MultipleFilters) { } TEST_F(SearchQueryParserTest, ExtraFilterAppended) { - QStringList searchColumns; - searchColumns << "artist"; - + m_parser.setSearchColumns({"artist"}); auto pQuery( - m_parser.parseQuery("asdf", searchColumns, "1 > 2")); + m_parser.parseQuery("asdf", "1 > 2")); TrackPointer pTrack = newTestTrack(44100); pTrack->setArtist("zxcv"); @@ -547,12 +480,9 @@ TEST_F(SearchQueryParserTest, ExtraFilterAppended) { } TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("duration:1:30", searchColumns, "")); + m_parser.parseQuery("duration:1:30", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->setDuration(91); @@ -564,7 +494,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) { qPrintable(QString("duration = 90")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:1m30s", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:1m30s", QString()); pTrack->setDuration(91); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); @@ -574,7 +504,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) { qPrintable(QString("duration = 90")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:90", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:90", QString()); pTrack->setDuration(91); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); @@ -586,12 +516,9 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) { } TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("duration:>1:30", searchColumns, "")); + m_parser.parseQuery("duration:>1:30", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->setDuration(89); @@ -602,7 +529,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration > 90")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:>=90", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:>=90", QString()); pTrack->setDuration(89); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); @@ -611,7 +538,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration >= 90")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:>=1:30", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:>=1:30", QString()); pTrack->setDuration(89); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); @@ -620,7 +547,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration >= 90")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<2:30", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<2:30", QString()); pTrack->setDuration(151); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(89); @@ -629,7 +556,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration < 150")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<=2:30", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<=2:30", QString()); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -638,7 +565,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration <= 150")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<=150", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<=150", QString()); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -647,7 +574,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration <= 150")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<=2m30s", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<=2m30s", QString()); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -656,7 +583,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration <= 150")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<=2m", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<=2m", QString()); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(110); @@ -665,7 +592,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration <= 120")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:<=2:", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:<=2:", QString()); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(110); @@ -674,7 +601,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { qPrintable(QString("duration <= 120")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:>=1:3", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:>=1:3", QString()); pTrack->setDuration(60); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -685,12 +612,9 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchWithOperators) { } TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { - QStringList searchColumns; - searchColumns << "artist" - << "album"; - + m_parser.setSearchColumns({"artist", "album"}); auto pQuery( - m_parser.parseQuery("duration:2:30-3:20", searchColumns, "")); + m_parser.parseQuery("duration:2:30-3:20", QString())); TrackPointer pTrack = newTestTrack(44100); pTrack->setDuration(80); @@ -704,7 +628,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { qPrintable(QString("(duration >= 150) AND (duration <= 200)")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:2:30-200", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:2:30-200", QString()); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -716,7 +640,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { qPrintable(QString("(duration >= 150) AND (duration <= 200)")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:150-200", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:150-200", QString()); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -728,7 +652,7 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { qPrintable(QString("(duration >= 150) AND (duration <= 200)")), qPrintable(pQuery->toSql())); - pQuery = m_parser.parseQuery("duration:2m30s-3m20s", searchColumns, ""); + pQuery = m_parser.parseQuery("duration:2m30s-3m20s", QString()); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); @@ -746,8 +670,7 @@ TEST_F(SearchQueryParserTest, CrateFilter) { QString searchTerm = "test"; // Parse the user query - auto pQuery(m_parser.parseQuery(QString("crate: %1").arg(searchTerm), - QStringList(), "")); + auto pQuery(m_parser.parseQuery(QString("crate: %1").arg(searchTerm), QString())); // locations for test tracks const QString kTrackALocationTest(QDir::currentPath() % @@ -784,14 +707,9 @@ TEST_F(SearchQueryParserTest, ShortCrateFilter) { // User's search term QString crateName = "somecrate"; QString searchTerm = "ecrat"; - QStringList searchColumns; - searchColumns << "crate" - << "artist" - << "comment"; - + m_parser.setSearchColumns({"crate", "artist", "comment"}); // Parse the user query - auto pQuery(m_parser.parseQuery(QString("%1").arg(searchTerm), - searchColumns, "")); + auto pQuery(m_parser.parseQuery(QString("%1").arg(searchTerm), QString())); // locations for test tracks const QString kTrackALocationTest(QDir::currentPath() % @@ -829,7 +747,7 @@ TEST_F(SearchQueryParserTest, ShortCrateFilter) { TEST_F(SearchQueryParserTest, CrateFilterEmpty) { // Empty should match everything - auto pQuery(m_parser.parseQuery(QString("crate: "), QStringList(), "")); + auto pQuery(m_parser.parseQuery(QString("crate: "), QString())); TrackPointer pTrackA(Track::newTemporary()); @@ -846,8 +764,7 @@ TEST_F(SearchQueryParserTest, CrateFilterQuote){ QString searchTerm = "test with whitespace"; // Parse the user query - auto pQuery(m_parser.parseQuery(QString("crate: \"%1\"").arg(searchTerm), - QStringList(), "")); + auto pQuery(m_parser.parseQuery(QString("crate: \"%1\"").arg(searchTerm), QString())); // locations for test tracks const QString kTrackALocationTest(QDir::currentPath() % @@ -890,8 +807,7 @@ TEST_F(SearchQueryParserTest, CrateFilterWithOther){ QString searchTerm = "test"; // Parse the user query - auto pQuery(m_parser.parseQuery(QString("crate: %1 artist: asdf").arg(searchTerm), - QStringList(), "")); + auto pQuery(m_parser.parseQuery(QString("crate: %1 artist: asdf").arg(searchTerm), QString())); // locations for test tracks const QString kTrackALocationTest(QDir::currentPath() % @@ -935,8 +851,9 @@ TEST_F(SearchQueryParserTest, CrateFilterWithCrateFilterAndNegation){ QString searchTermB = "testB"; // Parse the user query - auto pQueryA(m_parser.parseQuery(QString("crate: %1 crate: %2").arg(searchTermA, searchTermB), - QStringList(), "")); + auto pQueryA(m_parser.parseQuery( + QString("crate: %1 crate: %2").arg(searchTermA, searchTermB), + QString())); // locations for test tracks const QString kTrackALocationTest(QDir::currentPath() % @@ -979,8 +896,9 @@ TEST_F(SearchQueryParserTest, CrateFilterWithCrateFilterAndNegation){ qPrintable(pQueryA->toSql())); // parse again to test negation - auto pQueryB(m_parser.parseQuery(QString("crate: %1 -crate: %2").arg(searchTermA, searchTermB), - QStringList(), "")); + auto pQueryB(m_parser.parseQuery( + QString("crate: %1 -crate: %2").arg(searchTermA, searchTermB), + QString())); EXPECT_FALSE(pQueryB->match(pTrackA)); EXPECT_TRUE(pQueryB->match(pTrackB)); From 5fc7616d9a8c6852939edf828b244c1680e1fd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 00:06:58 +0100 Subject: [PATCH 24/75] Return false from Track::exportSeratoMetadata() in case of failure. --- src/track/track.cpp | 47 +++++++++++++++++++++++++-------------------- src/track/track.h | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/track/track.cpp b/src/track/track.cpp index 9f6c8b7c305..9f2a6286e1f 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -1373,7 +1373,7 @@ quint16 Track::getCoverHash() const { return m_record.getCoverInfo().hash; } -void Track::exportSeratoMetadata() { +bool Track::exportSeratoMetadata() { const auto streamInfo = m_record.getStreamInfoFromSource(); VERIFY_OR_DEBUG_ASSERT(streamInfo && streamInfo->getSignalInfo().isValid() && @@ -1381,32 +1381,37 @@ void Track::exportSeratoMetadata() { kLogger.warning() << "Cannot write Serato metadata because signal " "info and/or duration is not available:" << getLocation(); - return; + return false; } - const mixxx::audio::SampleRate sampleRate = - streamInfo->getSignalInfo().getSampleRate(); - mixxx::SeratoTags* seratoTags = + mixxx::SeratoTags* pSeratoTags = m_record.refMetadata().refTrackInfo().ptrSeratoTags(); - DEBUG_ASSERT(seratoTags); - if (seratoTags->status() == mixxx::SeratoTags::ParserStatus::Failed) { + VERIFY_OR_DEBUG_ASSERT(pSeratoTags) { + return false; + } + if (pSeratoTags->status() == mixxx::SeratoTags::ParserStatus::Failed) { kLogger.warning() << "Refusing to overwrite Serato metadata that failed to parse:" << getLocation(); - } else { - seratoTags->setTrackColor(getColor()); - seratoTags->setBpmLocked(isBpmLocked()); - QList cueInfos; - for (const CuePointer& pCue : qAsConst(m_cuePoints)) { - cueInfos.append(pCue->getCueInfo(sampleRate)); - } - const double timingOffset = mixxx::SeratoTags::guessTimingOffsetMillis( - getLocation(), streamInfo->getSignalInfo()); - seratoTags->setCueInfos(cueInfos, timingOffset); - seratoTags->setBeats(m_pBeats, - streamInfo->getSignalInfo(), - streamInfo->getDuration(), - timingOffset); + return false; + } + pSeratoTags->setTrackColor(getColor()); + pSeratoTags->setBpmLocked(isBpmLocked()); + + const mixxx::audio::SampleRate sampleRate = + streamInfo->getSignalInfo().getSampleRate(); + QList cueInfos; + for (const CuePointer& pCue : qAsConst(m_cuePoints)) { + cueInfos.append(pCue->getCueInfo(sampleRate)); } + + const double timingOffset = mixxx::SeratoTags::guessTimingOffsetMillis( + getLocation(), streamInfo->getSignalInfo()); + pSeratoTags->setCueInfos(cueInfos, timingOffset); + pSeratoTags->setBeats(m_pBeats, + streamInfo->getSignalInfo(), + streamInfo->getDuration(), + timingOffset); + return true; } ExportTrackMetadataResult Track::exportMetadata( diff --git a/src/track/track.h b/src/track/track.h index 11ca0b1a9bf..b14ad38c5c8 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -450,7 +450,7 @@ class Track : public QObject { }; double getDuration(DurationRounding rounding) const; - void exportSeratoMetadata(); + bool exportSeratoMetadata(); ExportTrackMetadataResult exportMetadata( mixxx::MetadataSourcePointer pMetadataSource, From 3fcfa16cea3ecaa62b677856bb50b2f0a63c44ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 00:12:03 +0100 Subject: [PATCH 25/75] Remove pointless comments Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- src/library/banshee/bansheeplaylistmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 38a5bc87248..722c8263459 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -215,10 +215,10 @@ void BansheePlaylistModel::setTableModel(int playlistId) { QStringList tableColumns = { kTrackId, kViewOrder, - kPreview}; // 3 + kPreview}; QStringList trackSourceColumns = { - kTrackId, // 0 + kTrackId, KArtist, KTitel, kDuration, From 5805b1775ad902e20bb805be48b821579ad36345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 00:25:43 +0100 Subject: [PATCH 26/75] Make use of SharedPointer::create to avoid a literally new, --- src/library/banshee/bansheeplaylistmodel.cpp | 14 +++++++------- src/library/itunes/itunesfeature.cpp | 4 ++-- src/library/rekordbox/rekordboxfeature.cpp | 14 +++++++------- src/library/rhythmbox/rhythmboxfeature.cpp | 14 +++++++------- src/library/serato/seratofeature.cpp | 14 +++++++------- src/library/traktor/traktorfeature.cpp | 4 ++-- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 722c8263459..a2755d26eb4 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -246,13 +246,13 @@ void BansheePlaylistModel::setTableModel(int playlistId) { KTitel, kGenre}; - QSharedPointer trackSource( - new BaseTrackCache(m_pTrackCollectionManager->internalCollection(), - m_tempTableName, - idColumn, - std::move(trackSourceColumns), - std::move(searchColumns), - false)); + auto trackSource = QSharedPointer::create( + m_pTrackCollectionManager->internalCollection(), + m_tempTableName, + idColumn, + std::move(trackSourceColumns), + std::move(searchColumns), + false); setTable(m_tempTableName, idColumn, std::move(tableColumns), trackSource); setSearch(""); diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index b193ace2f20..8c773998a5c 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -94,13 +94,13 @@ ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) "title", "genre"}; - m_trackSource = QSharedPointer(new BaseTrackCache( + m_trackSource = QSharedPointer::create( m_pLibrary->trackCollections()->internalCollection(), std::move(tableName), std::move(idColumn), std::move(columns), std::move(searchColumns), - false)); + false); m_pITunesTrackModel = new BaseExternalTrackModel( this, m_pLibrary->trackCollections(), "mixxx.db.model.itunes", diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 6f9e596cd8b..bd2692a8c14 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1262,13 +1262,13 @@ RekordboxFeature::RekordboxFeature( TRACKLOCATIONSTABLE_LOCATION, LIBRARYTABLE_COMMENT}; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, - tableName, - std::move(idColumn), - std::move(columns), - std::move(searchColumns), - false)); + m_trackSource = QSharedPointer::create( + m_pTrackCollection, + tableName, + std::move(idColumn), + std::move(columns), + std::move(searchColumns), + false); m_pRekordboxPlaylistModel = make_parented( this, pLibrary->trackCollections(), m_trackSource); diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index 468ac88bd20..eb029e0fae0 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -42,13 +42,13 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfi "title", "genre"}; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, - tableName, - std::move(idColumn), - std::move(columns), - std::move(searchColumns), - false)); + m_trackSource = QSharedPointer::create( + m_pTrackCollection, + tableName, + std::move(idColumn), + std::move(columns), + std::move(searchColumns), + false); m_pRhythmboxTrackModel = new BaseExternalTrackModel( this, pLibrary->trackCollections(), diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 95c16e305c3..d2d62d837d1 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -880,13 +880,13 @@ SeratoFeature::SeratoFeature( LIBRARYTABLE_COMMENT, LIBRARYTABLE_GROUPING}; - m_trackSource = QSharedPointer( - new BaseTrackCache(m_pTrackCollection, - kSeratoLibraryTable, - std::move(idColumn), - std::move(columns), - std::move(searchColumns), - false)); + m_trackSource = QSharedPointer::create( + m_pTrackCollection, + kSeratoLibraryTable, + std::move(idColumn), + std::move(columns), + std::move(searchColumns), + false); m_pSeratoPlaylistModel = new SeratoPlaylistModel(this, pLibrary->trackCollections(), m_trackSource); m_title = tr("Serato"); diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 963229c2d08..7a0e7b91f45 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -92,13 +92,13 @@ TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) "title", "genre"}; - m_trackSource = QSharedPointer(new BaseTrackCache( + m_trackSource = QSharedPointer::create( pLibrary->trackCollections()->internalCollection(), tableName, std::move(idColumn), std::move(columns), std::move(searchColumns), - false)); + false); m_isActivated = false; m_pTraktorTableModel = new TraktorTrackModel(this, pLibrary->trackCollections(), m_trackSource); From 155fad8cc1db9e32b37cb2b1b876b23379225e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 07:54:15 +0100 Subject: [PATCH 27/75] Fix naming of contsnats --- src/library/banshee/bansheeplaylistmodel.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index a2755d26eb4..961f51813d8 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -42,8 +42,8 @@ QAtomicInt sTableNumber; const QString kTrackId = QStringLiteral(CLM_TRACK_ID); const QString kViewOrder = QStringLiteral(CLM_VIEW_ORDER); -const QString KArtist = QStringLiteral(CLM_ARTIST); -const QString KTitel = QStringLiteral(CLM_TITLE); +const QString kArtist = QStringLiteral(CLM_ARTIST); +const QString kTitle = QStringLiteral(CLM_TITLE); const QString kDuration = QStringLiteral(CLM_DURATION); const QString kUri = QStringLiteral(CLM_URI); const QString kAlbum = QStringLiteral(CLM_ALBUM); @@ -219,8 +219,8 @@ void BansheePlaylistModel::setTableModel(int playlistId) { QStringList trackSourceColumns = { kTrackId, - KArtist, - KTitel, + kArtist, + kTitle, kDuration, kUri, kAlbum, @@ -237,13 +237,13 @@ void BansheePlaylistModel::setTableModel(int playlistId) { kPlaycount, kComposer}; QStringList searchColumns = { - KArtist, + kArtist, kAlbum, kAlbumArtist, kUri, kGrouping, kComment, - KTitel, + kTitle, kGenre}; auto trackSource = QSharedPointer::create( From c21d9196caa47a0ce1d0a0b55bc779b14a59e3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 07:58:18 +0100 Subject: [PATCH 28/75] Prefere QModelIndex(); when resetting stored indexes. --- src/library/baseexternallibraryfeature.h | 2 +- src/library/baseplaylistfeature.cpp | 2 +- src/library/crate/cratefeature.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index 9aa436ee814..a13c399e757 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -46,7 +46,7 @@ class BaseExternalLibraryFeature : public LibraryFeature { return m_lastRightClickedIndex; } void clearLastRightClickedIndex() { - m_lastRightClickedIndex = {}; + m_lastRightClickedIndex = QModelIndex(); }; TrackCollection* const m_pTrackCollection; diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index bc66aacd107..d9003459b6c 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -671,7 +671,7 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { * Clears the child model dynamically, but the invisible root item remains */ void BasePlaylistFeature::clearChildModel() { - m_lastRightClickedIndex = {}; + m_lastRightClickedIndex = QModelIndex(); m_childModel.removeRows(0, m_childModel.rowCount()); } diff --git a/src/library/crate/cratefeature.cpp b/src/library/crate/cratefeature.cpp index 88f1a1989f3..5e09448acdf 100644 --- a/src/library/crate/cratefeature.cpp +++ b/src/library/crate/cratefeature.cpp @@ -479,7 +479,7 @@ void CrateFeature::slotAutoDjTrackSourceChanged() { QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { qDebug() << "CrateFeature::rebuildChildModel()" << selectedCrateId; - m_lastRightClickedIndex = {}; + m_lastRightClickedIndex = QModelIndex(); TreeItem* pRootItem = m_childModel.getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { From e7ffb3971228159856b11fbc0b115cfa523950cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 08:01:26 +0100 Subject: [PATCH 29/75] use std::make_unique when initalize m_pQueryParser --- src/library/basetrackcache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp index c2d44106c1c..ae3931bf19f 100644 --- a/src/library/basetrackcache.cpp +++ b/src/library/basetrackcache.cpp @@ -27,7 +27,8 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection, m_columnCount(columns.size()), m_columnsJoined(columns.join(",")), m_columnCache(std::move(columns)), - m_pQueryParser(new SearchQueryParser(pTrackCollection, std::move(searchColumns))), + m_pQueryParser(std::make_unique( + pTrackCollection, std::move(searchColumns))), m_bIndexBuilt(false), m_bIsCaching(isCaching), m_database(pTrackCollection->database()) { From 6f7ed40c9097ec31b6887d08bbbbb565736af78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 08:06:48 +0100 Subject: [PATCH 30/75] Improve the comment about QFuture --- src/library/serato/seratofeature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index d2d62d837d1..739960cd865 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -670,7 +670,7 @@ QString parseDatabase(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dat // This function is executed in a separate thread other than the main thread // The returned list owns the pointers, but we can't use a unique_ptr because -// the result is passed by a const reference +// the result is passed by a const reference inside QFuture. QList findSeratoDatabases() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); From 904ad3afbe0aaa4ad1526e0733c3b62b9b6096e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 08:21:54 +0100 Subject: [PATCH 31/75] Use iterator-based construction --- src/library/rekordbox/rekordboxfeature.cpp | 7 ++----- src/library/serato/seratofeature.cpp | 6 ++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index bd2692a8c14..7c39a7090c9 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -163,7 +163,7 @@ bool dropTable(QSqlDatabase& database, const QString& tableName) { // This function is executed in a separate thread other than the main thread // The returned list owns the pointers, but we can't use a unique_ptr because -// the result is passed by a const reference +// the result is passed by a const reference inside QFuture. QList findRekordboxDevices() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); @@ -1458,11 +1458,8 @@ void RekordboxFeature::activateChild(const QModelIndex& index) { } void RekordboxFeature::onRekordboxDevicesFound() { - std::vector> foundDevices; const QList result = m_devicesFuture.result(); - for (const auto& pDeviceFound : result) { - foundDevices.emplace_back(pDeviceFound); - } + auto foundDevices = std::vector>(result.cbegin(), result.cend()); clearLastRightClickedIndex(); diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 739960cd865..b595290095e 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -1062,11 +1062,9 @@ void SeratoFeature::activateChild(const QModelIndex& index) { } void SeratoFeature::onSeratoDatabasesFound() { - std::vector> foundDatabases; + // std::vector> foundDatabases; const QList result = m_databasesFuture.result(); - for (const auto& pDatabaseFound : result) { - foundDatabases.emplace_back(pDatabaseFound); - } + auto foundDatabases = std::vector>(result.cbegin(), result.cend()); clearLastRightClickedIndex(); From c77e18acaed1a3977a8c5cf61fdfa5636bdeaf7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 08:23:14 +0100 Subject: [PATCH 32/75] Remove redundant type name --- src/library/treeitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/treeitem.cpp b/src/library/treeitem.cpp index b509dc2e18c..9861cea281e 100644 --- a/src/library/treeitem.cpp +++ b/src/library/treeitem.cpp @@ -85,7 +85,7 @@ void TreeItem::initFeatureRecursively(LibraryFeature* pFeature) { TreeItem* TreeItem::appendChild( QString label, QVariant data) { - std::unique_ptr pNewChild = std::make_unique( + auto pNewChild = std::make_unique( std::move(label), std::move(data)); TreeItem* pRet = pNewChild.get(); From a48a5ed05b540dd358c689e63e8d4448c835eed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 17:03:52 +0100 Subject: [PATCH 33/75] Remove stary comment Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- src/library/serato/seratofeature.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index b595290095e..1ab0b360fb2 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -1062,7 +1062,6 @@ void SeratoFeature::activateChild(const QModelIndex& index) { } void SeratoFeature::onSeratoDatabasesFound() { - // std::vector> foundDatabases; const QList result = m_databasesFuture.result(); auto foundDatabases = std::vector>(result.cbegin(), result.cend()); From 54e0902400028439a91bc80846ec6e8b4f73123e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 17:19:45 +0100 Subject: [PATCH 34/75] Describe the issue with QFuture and std::unique_ptr() a bit more --- src/library/rekordbox/rekordboxfeature.cpp | 3 ++- src/library/serato/seratofeature.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 7c39a7090c9..f582b545b1f 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -163,7 +163,8 @@ bool dropTable(QSqlDatabase& database, const QString& tableName) { // This function is executed in a separate thread other than the main thread // The returned list owns the pointers, but we can't use a unique_ptr because -// the result is passed by a const reference inside QFuture. +// the result is passed by a const reference inside QFuture and than copied +// to the main thread requiring a copy-able object. QList findRekordboxDevices() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 1ab0b360fb2..c0eb1918d40 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -670,7 +670,8 @@ QString parseDatabase(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dat // This function is executed in a separate thread other than the main thread // The returned list owns the pointers, but we can't use a unique_ptr because -// the result is passed by a const reference inside QFuture. +// the result is passed by a const reference inside QFuture and than copied +// to the main thread requiring a copy-able object. QList findSeratoDatabases() { QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowPriority); From 4f49ed7fbf9a9892bad59388f30cf0733495d9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 17:28:26 +0100 Subject: [PATCH 35/75] Document decorateChild() --- src/library/baseplaylistfeature.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/baseplaylistfeature.h b/src/library/baseplaylistfeature.h index a1c1ab10382..4d6370ffc91 100644 --- a/src/library/baseplaylistfeature.h +++ b/src/library/baseplaylistfeature.h @@ -70,6 +70,8 @@ class BasePlaylistFeature : public BaseTrackSetFeature { virtual void clearChildModel(); virtual QList createPlaylistLabels() = 0; virtual QString fetchPlaylistLabel(int playlistId) = 0; + + /// borrows pChild which must not be null, TODO: use gsl::not_null virtual void decorateChild(TreeItem* pChild, int playlistId) = 0; virtual void addToAutoDJ(PlaylistDAO::AutoDJSendLoc loc); From 384d275265eee437e63581db29261d310346e059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 Jan 2023 20:37:49 +0100 Subject: [PATCH 36/75] use auto in connection with std::make_unique --- src/library/baseplaylistfeature.cpp | 2 +- src/library/itunes/itunesfeature.cpp | 13 ++++++------- src/library/rekordbox/rekordboxfeature.cpp | 5 ++--- src/library/searchqueryparser.cpp | 4 +--- src/library/serato/seratofeature.cpp | 5 ++--- src/library/traktor/traktorfeature.cpp | 5 ++--- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index d9003459b6c..27e1ed7d22e 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -633,7 +633,7 @@ QModelIndex BasePlaylistFeature::constructChildModel(int selected_id) { } // Create the TreeItem whose parent is the invisible root item - std::unique_ptr pItem = std::make_unique(playlistLabel, playlistId); + auto pItem = std::make_unique(playlistLabel, playlistId); pItem->setBold(m_playlistsSelectedTrackIsIn.contains(playlistId)); decorateChild(pItem.get(), playlistId); diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 8c773998a5c..09c3e4fa404 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -137,13 +137,12 @@ ITunesFeature::~ITunesFeature() { std::unique_ptr ITunesFeature::createPlaylistModelForPlaylist(const QString& playlist) { - std::unique_ptr pModel = - std::make_unique(this, - m_pLibrary->trackCollections(), - "mixxx.db.model.itunes_playlist", - "itunes_playlists", - "itunes_playlist_tracks", - m_trackSource); + auto pModel = std::make_unique(this, + m_pLibrary->trackCollections(), + "mixxx.db.model.itunes_playlist", + "itunes_playlists", + "itunes_playlist_tracks", + m_trackSource); pModel->setPlaylist(playlist); return pModel; } diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index f582b545b1f..a8928c87e8e 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1333,9 +1333,8 @@ void RekordboxFeature::htmlLinkClicked(const QUrl& link) { std::unique_ptr RekordboxFeature::createPlaylistModelForPlaylist(const QString& playlist) { - std::unique_ptr pModel = - std::make_unique( - this, m_pLibrary->trackCollections(), m_trackSource); + auto pModel = std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); pModel->setPlaylist(playlist); return pModel; } diff --git a/src/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 3873bc60d81..a015e1b4621 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -227,13 +227,11 @@ void SearchQueryParser::parseTokens(QStringList tokens, // as the crate names the track is in. This allows the user // to use crates like tags if (m_searchCrates) { - std::unique_ptr gNode = std::make_unique(); - + auto gNode = std::make_unique(); gNode->addNode(std::make_unique( &m_pTrackCollection->crates(), argument)); gNode->addNode(std::make_unique( m_pTrackCollection->database(), m_queryColumns, argument)); - pNode = std::move(gNode); } else { pNode = std::make_unique( diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index c0eb1918d40..81768677fdf 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -953,9 +953,8 @@ void SeratoFeature::htmlLinkClicked(const QUrl& link) { std::unique_ptr SeratoFeature::createPlaylistModelForPlaylist(const QString& playlist) { - std::unique_ptr pModel = - std::make_unique( - this, m_pLibrary->trackCollections(), m_trackSource); + auto pModel = std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); pModel->setPlaylist(playlist); return pModel; } diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 7a0e7b91f45..3bbc1670963 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -130,9 +130,8 @@ TraktorFeature::~TraktorFeature() { std::unique_ptr TraktorFeature::createPlaylistModelForPlaylist(const QString& playlist) { - std::unique_ptr pModel = - std::make_unique( - this, m_pLibrary->trackCollections(), m_trackSource); + auto pModel = std::make_unique( + this, m_pLibrary->trackCollections(), m_trackSource); pModel->setPlaylist(playlist); return pModel; } From d71b91e0eab8f567d2deecaae70fc421129adbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 2 Feb 2023 23:42:55 +0100 Subject: [PATCH 37/75] Add todos for introducing a std::span to simplifx the one element case --- src/library/autodj/autodjfeature.cpp | 2 ++ src/library/browse/browsefeature.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index d500416cd53..6c2823f0604 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -216,6 +216,8 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { } // No child item for crate found // -> Create and append a new child item for this crate + // TODO() Use here std::span to get around the heap alloctaion of + // std::vector for a single element. std::vector> rows; rows.push_back(std::make_unique(crate.getName(), crate.getId().toVariant())); QModelIndex parentIndex = m_childModel.index(0, 0); diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 2dcdc46b51f..fd521d04ec0 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -152,6 +152,8 @@ void BrowseFeature::slotAddQuickLink() { QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); std::vector> rows; + // TODO() Use here std::span to get around the heap allocation of + // std::vector for a single element. rows.push_back(std::make_unique(name, vpath)); m_childModel.insertTreeItemRows(std::move(rows), m_pQuickLinkItem->childRows(), parent); From 4834e90e13a62a1d865237e4c62756c965f04137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 3 Feb 2023 14:48:33 +0100 Subject: [PATCH 38/75] Add comments about the risk of dangling pointers --- src/library/baseexternallibraryfeature.cpp | 3 ++- src/library/baseexternallibraryfeature.h | 2 ++ src/library/browse/browsefeature.cpp | 2 ++ src/library/browse/browsefeature.h | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 4a3b81a82ab..dc646a8c8b6 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -58,7 +58,8 @@ void BaseExternalLibraryFeature::onRightClick(const QPoint& globalPos) { void BaseExternalLibraryFeature::onRightClickChild( const QPoint& globalPos, const QModelIndex& index) { - //Save the model index so we can get it in the action slots... + // Save the model index so we can get it in the action slots... + // Make sure that this is reset when the related TreeItem is deleted. m_lastRightClickedIndex = index; QMenu menu(m_pSidebarWidget); menu.addAction(m_pAddToAutoDJAction); diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index a13c399e757..9e1248a266d 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -54,6 +54,8 @@ class BaseExternalLibraryFeature : public LibraryFeature { private: void addToAutoDJ(PlaylistDAO::AutoDJSendLoc loc); + // Caution: Make sure this is reset whenever the library tree is updated, + // so that the internalPointer() does not become dangling QModelIndex m_lastRightClickedIndex; parented_ptr m_pAddToAutoDJAction; diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index fd521d04ec0..5c45a3f4083 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -273,6 +273,8 @@ void BrowseFeature::activateChild(const QModelIndex& index) { void BrowseFeature::onRightClickChild(const QPoint& globalPos, const QModelIndex& index) { TreeItem *item = static_cast(index.internalPointer()); + + // Make sure that this is reset when the related TreeItem is deleted. m_pLastRightClickedItem = item; if (!item) { diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h index a90fdded19a..c98e9538c77 100644 --- a/src/library/browse/browsefeature.h +++ b/src/library/browse/browsefeature.h @@ -70,6 +70,9 @@ class BrowseFeature : public LibraryFeature { QAction* m_pAddQuickLinkAction; QAction* m_pRemoveQuickLinkAction; QAction* m_pAddtoLibraryAction; + + // Caution: Make sure this is reset whenever the library tree is updated, + // so that the internalPointer() does not become dangling TreeItem* m_pLastRightClickedItem; TreeItem* m_pQuickLinkItem; QStringList m_quickLinkList; From 7cd0707709bf8c2f3114182c9eaf0d019a6f4339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 09:50:22 +0100 Subject: [PATCH 39/75] Move getTrackValueForColumn() to an anonymous namespace --- src/library/searchquery.cpp | 4 ++++ src/library/searchquery.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index b17785a359b..89aa141baa0 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -10,6 +10,8 @@ #include "util/db/dbconnection.h" #include "util/db/sqllikewildcards.h" +namespace { + QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& column) { if (column == LIBRARYTABLE_ARTIST) { return pTrack->getArtist(); @@ -60,6 +62,8 @@ QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& colum return QVariant(); } +} // namespace + //static QString QueryNode::concatSqlClauses( const QStringList& sqlClauses, const QString& sqlConcatOp) { diff --git a/src/library/searchquery.h b/src/library/searchquery.h index b8caa0d54f4..5e6251bf913 100644 --- a/src/library/searchquery.h +++ b/src/library/searchquery.h @@ -17,8 +17,6 @@ const QString kMissingFieldSearchTerm = "\"\""; // "" searches for an empty string -QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& column); - class QueryNode { public: QueryNode(const QueryNode&) = delete; // prevent copying From 81fddd6d2e465087f80409f00d35ee992f483ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 11:36:06 +0100 Subject: [PATCH 40/75] Move concatSqlClauses() to the anonymous namespace --- src/library/searchquery.cpp | 7 +++---- src/library/searchquery.h | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 89aa141baa0..d3ad8735633 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -62,10 +62,7 @@ QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& colum return QVariant(); } -} // namespace - -//static -QString QueryNode::concatSqlClauses( +QString concatSqlClauses( const QStringList& sqlClauses, const QString& sqlConcatOp) { switch (sqlClauses.size()) { case 0: @@ -80,6 +77,8 @@ QString QueryNode::concatSqlClauses( } } +} // namespace + bool AndNode::match(const TrackPointer& pTrack) const { for (const auto& pNode: m_nodes) { if (!pNode->match(pTrack)) { diff --git a/src/library/searchquery.h b/src/library/searchquery.h index 5e6251bf913..26dec40547a 100644 --- a/src/library/searchquery.h +++ b/src/library/searchquery.h @@ -27,8 +27,6 @@ class QueryNode { protected: QueryNode() {} - - static QString concatSqlClauses(const QStringList& sqlClauses, const QString& sqlConcatOp); }; class GroupNode : public QueryNode { From 5d7c318ce8cb3a25bd05a9f81add4a6a6226b5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 11:37:32 +0100 Subject: [PATCH 41/75] Make use of QStringLiteral() in concatSqlClauses() --- src/library/searchquery.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index d3ad8735633..834cdc8c745 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -73,7 +73,10 @@ QString concatSqlClauses( // The component terms need to be wrapped into parentheses, // but the whole expression does not. The composite node is // always responsible for proper wrapping into parentheses! - return "(" % sqlClauses.join(") " % sqlConcatOp % " (") % ")"; + return QChar('(') + + sqlClauses.join( + QStringLiteral(") ") + sqlConcatOp + QStringLiteral(" (")) + + QChar(')'); } } From 76c6efc3dfb8aba6fa46a75622c582f93c8e1913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 12:07:49 +0100 Subject: [PATCH 42/75] Match only the year when using the "year:" search token. --- src/library/searchquery.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 834cdc8c745..6e7511f2dc4 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -22,7 +22,9 @@ QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& colum } else if (column == LIBRARYTABLE_ALBUMARTIST) { return pTrack->getAlbumArtist(); } else if (column == LIBRARYTABLE_YEAR) { - return pTrack->getYear(); + // We use only the year that is part of the first four digits + // In all possible formats. + return pTrack->getYear().left(4); } else if (column == LIBRARYTABLE_DATETIMEADDED) { return pTrack->getDateAdded(); } else if (column == LIBRARYTABLE_GENRE) { From 88573a04e748702af946c9b76193a59bff7533c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 13:13:55 +0100 Subject: [PATCH 43/75] Add a YearFilterNode for matching the year only --- src/library/searchquery.cpp | 28 ++++++++++++++++++++++++++++ src/library/searchquery.h | 6 +++++- src/library/searchqueryparser.cpp | 15 +++++++++------ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 6e7511f2dc4..76c325f4739 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -466,3 +466,31 @@ QString KeyFilterNode::toSql() const { } return concatSqlClauses(searchClauses, "OR"); } + +YearFilterNode::YearFilterNode( + const QStringList& sqlColumns, const QString& argument) + : NumericFilterNode(sqlColumns, argument) { +} + +QString YearFilterNode::toSql() const { + if (m_bNullQuery) { + return QStringLiteral("year IS NULL"); + } + + if (m_bOperatorQuery) { + return QString( + QStringLiteral("CAST(substr(year,1,4) AS INTEGER) %1 %2")) + .arg(m_operator, QString::number(m_dOperatorArgument)); + } + + if (m_bRangeQuery) { + QStringList rangeClauses; + return QString( + QStringLiteral("(CAST(substr(year,1,4) AS INTEGER) >= %1) AND " + "(CAST(substr(year,1,4) AS INTEGER) <= %2)")) + .arg(QString::number(m_dRangeLow), + QString::number(m_dRangeHigh)); + } + + return QString(); +} diff --git a/src/library/searchquery.h b/src/library/searchquery.h index 26dec40547a..28d3a84d75b 100644 --- a/src/library/searchquery.h +++ b/src/library/searchquery.h @@ -147,7 +147,6 @@ class NumericFilterNode : public QueryNode { // derived classes. void init(QString argument); - private: virtual double parse(const QString& arg, bool *ok); QStringList m_sqlColumns; @@ -213,5 +212,10 @@ class SqlNode : public QueryNode { QString m_sql; }; +class YearFilterNode : public NumericFilterNode { + public: + YearFilterNode(const QStringList& sqlColumns, const QString& argument); + QString toSql() const override; +}; #endif /* SEARCHQUERY_H */ diff --git a/src/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 85352b3ad3f..f4a879aa929 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -19,13 +19,13 @@ SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection) << "comment" << "location" << "crate"; - m_numericFilters << "year" - << "track" + m_numericFilters << "track" << "bpm" << "played" << "rating" << "bitrate"; - m_specialFilters << "key" + m_specialFilters << "year" + << "key" << "duration" << "added" << "dateadded" @@ -204,10 +204,13 @@ void SearchQueryParser::parseTokens(QStringList tokens, } else if (field == "duration") { pNode = std::make_unique( m_fieldToSqlColumns[field], argument); + } else if (field == "year") { + pNode = std::make_unique( + m_fieldToSqlColumns[field], argument); } else if (field == "date_added" || - field == "datetime_added" || - field == "added" || - field == "dateadded") { + field == "datetime_added" || + field == "added" || + field == "dateadded") { field = "datetime_added"; pNode = std::make_unique( m_pTrackCollection->database(), m_fieldToSqlColumns[field], argument); From 8fa23c489aea7c736765d3c8be565c781b410faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 13:20:09 +0100 Subject: [PATCH 44/75] Added test for the new YearFilterNode --- src/test/searchqueryparsertest.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index ae333c6a67d..195239465a5 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -382,6 +382,27 @@ TEST_F(SearchQueryParserTest, NumericFilter) { qPrintable(pQuery->toSql())); } +TEST_F(SearchQueryParserTest, NumericFilterYear) { + QStringList searchColumns; + searchColumns << "year"; + + auto pQuery( + m_parser.parseQuery("year:1969", searchColumns, "")); + + TrackPointer pTrack = newTestTrack(44100); + EXPECT_FALSE(pQuery->match(pTrack)); + pTrack->setYear(" 1969-08-15 "); + EXPECT_TRUE(pQuery->match(pTrack)); + pTrack->setYear(" 19690815 "); + EXPECT_TRUE(pQuery->match(pTrack)); + pTrack->setYear(" 1969-extra "); + EXPECT_TRUE(pQuery->match(pTrack)); + + EXPECT_STREQ( + qPrintable(QStringLiteral("CAST(substr(year,1,4) AS INTEGER) = 1969")), + qPrintable(pQuery->toSql())); +} + TEST_F(SearchQueryParserTest, NumericFilterEmpty) { QStringList searchColumns; searchColumns << "artist" From 6e268181e9bda076bfe06c721499441fefc500a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Feb 2023 13:41:43 +0100 Subject: [PATCH 45/75] Make use of sqlite BETWEEN and adjust test accordingly --- src/library/searchquery.cpp | 13 +++++-------- src/test/searchqueryparsertest.cpp | 31 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 76c325f4739..b3186e74bd6 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -371,12 +371,10 @@ QString NumericFilterNode::toSql() const { if (m_bRangeQuery) { QStringList searchClauses; for (const auto& sqlColumn: m_sqlColumns) { - QStringList rangeClauses; - rangeClauses << QString("%1 >= %2").arg( - sqlColumn, QString::number(m_dRangeLow)); - rangeClauses << QString("%1 <= %2").arg( - sqlColumn, QString::number(m_dRangeHigh)); - searchClauses << concatSqlClauses(rangeClauses, "AND"); + searchClauses << QString(QStringLiteral("%1 BETWEEN %2 AND %3")) + .arg(sqlColumn, + QString::number(m_dRangeLow), + QString::number(m_dRangeHigh)); } return concatSqlClauses(searchClauses, "OR"); } @@ -486,8 +484,7 @@ QString YearFilterNode::toSql() const { if (m_bRangeQuery) { QStringList rangeClauses; return QString( - QStringLiteral("(CAST(substr(year,1,4) AS INTEGER) >= %1) AND " - "(CAST(substr(year,1,4) AS INTEGER) <= %2)")) + QStringLiteral("CAST(substr(year,1,4) AS INTEGER) BETWEEN %1 AND %2")) .arg(QString::number(m_dRangeLow), QString::number(m_dRangeHigh)); } diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index 195239465a5..30152b5170c 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -521,8 +521,8 @@ TEST_F(SearchQueryParserTest, NumericRangeFilter) { EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( - qPrintable(QString("(bpm >= 127.12) AND (bpm <= 129)")), - qPrintable(pQuery->toSql())); + qPrintable(QString("bpm BETWEEN 127.12 AND 129")), + qPrintable(pQuery->toSql())); } TEST_F(SearchQueryParserTest, MultipleFilters) { @@ -542,11 +542,12 @@ TEST_F(SearchQueryParserTest, MultipleFilters) { pTrack->setTitle("Colorvision"); EXPECT_TRUE(pQuery->match(pTrack)); - EXPECT_STREQ( - qPrintable(QString("((bpm >= 127.12) AND (bpm <= 129)) AND " - "((artist LIKE '%com truise%') OR (album_artist LIKE '%com truise%')) AND " - "((artist LIKE '%colorvision%') OR (title LIKE '%colorvision%'))")), - qPrintable(pQuery->toSql())); + EXPECT_STREQ(qPrintable(QString("(bpm BETWEEN 127.12 AND 129) AND " + "((artist LIKE '%com truise%') OR " + "(album_artist LIKE '%com truise%')) AND " + "((artist LIKE '%colorvision%') OR (title " + "LIKE '%colorvision%'))")), + qPrintable(pQuery->toSql())); } TEST_F(SearchQueryParserTest, ExtraFilterAppended) { @@ -722,8 +723,8 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( - qPrintable(QString("(duration >= 150) AND (duration <= 200)")), - qPrintable(pQuery->toSql())); + qPrintable(QString("duration BETWEEN 150 AND 200")), + qPrintable(pQuery->toSql())); pQuery = m_parser.parseQuery("duration:2:30-200", searchColumns, ""); pTrack->setDuration(80); @@ -734,8 +735,8 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( - qPrintable(QString("(duration >= 150) AND (duration <= 200)")), - qPrintable(pQuery->toSql())); + qPrintable(QString("duration BETWEEN 150 AND 200")), + qPrintable(pQuery->toSql())); pQuery = m_parser.parseQuery("duration:150-200", searchColumns, ""); pTrack->setDuration(80); @@ -746,8 +747,8 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( - qPrintable(QString("(duration >= 150) AND (duration <= 200)")), - qPrintable(pQuery->toSql())); + qPrintable(QString("duration BETWEEN 150 AND 200")), + qPrintable(pQuery->toSql())); pQuery = m_parser.parseQuery("duration:2m30s-3m20s", searchColumns, ""); pTrack->setDuration(80); @@ -758,8 +759,8 @@ TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( - qPrintable(QString("(duration >= 150) AND (duration <= 200)")), - qPrintable(pQuery->toSql())); + qPrintable(QString("duration BETWEEN 150 AND 200")), + qPrintable(pQuery->toSql())); } TEST_F(SearchQueryParserTest, CrateFilter) { From 05c9b5a5ae9b8d381935b727dff43490aa370dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 7 Feb 2023 07:34:37 +0100 Subject: [PATCH 46/75] Remove redundant comments from track.h --- src/track/track.h | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/src/track/track.h b/src/track/track.h index 6f9e1d8e7ef..c85aa50e11a 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -80,7 +80,6 @@ class Track : public QObject { } // The (refreshed) canonical location QString getCanonicalLocation() const; - // Checks if the file exists bool checkFileExists() const { return m_fileInfo.checkFileExists(); } @@ -92,14 +91,10 @@ class Track : public QObject { // Get number of channels int getChannels() const; - // Get sample rate mixxx::audio::SampleRate getSampleRate() const; - // Sets the bitrate void setBitrate(int); - // Returns the bitrate int getBitrate() const; - // Returns the bitrate as a string QString getBitrateText() const; void setDuration(mixxx::Duration duration); @@ -128,12 +123,10 @@ class Track : public QObject { // Sets the BPM if not locked. bool trySetBpm(double bpm); - // Returns BPM double getBpm() const { const QMutexLocker lock(&m_qMutex); return getBpmWhileLocked().getValue(); } - // Returns BPM as a string QString getBpmText() const; // A track with a locked BPM will not be re-analyzed by the beats or bpm @@ -141,9 +134,7 @@ class Track : public QObject { void setBpmLocked(bool bpmLocked); bool isBpmLocked() const; - // Set ReplayGain void setReplayGain(const mixxx::ReplayGain&); - // Returns ReplayGain mixxx::ReplayGain getReplayGain() const; // Indicates if the metadata has been parsed from file tags. @@ -154,47 +145,29 @@ class Track : public QObject { void setDateAdded(const QDateTime& dateAdded); QDateTime getDateAdded() const; - // Getter/Setter methods for metadata - // Return title QString getTitle() const; - // Set title void setTitle(const QString&); - // Return artist QString getArtist() const; - // Set artist void setArtist(const QString&); - // Return album QString getAlbum() const; - // Set album void setAlbum(const QString&); - // Return album artist QString getAlbumArtist() const; - // Set album artist void setAlbumArtist(const QString&); - // Return Year + QString getYear() const; - // Set year void setYear(const QString&); - // Return genre + QString getGenre() const; - // Set genre void setGenre(const QString&); - // Returns the track color mixxx::RgbColor::optional_t getColor() const; - // Sets the track color void setColor(mixxx::RgbColor::optional_t); - // Returns the user comment QString getComment() const; - // Sets the user comment void setComment(const QString&); - // Return composer QString getComposer() const; - // Set composer void setComposer(const QString&); - // Return grouping QString getGrouping() const; - // Set grouping void setGrouping(const QString&); + // Return track number/total QString getTrackNumber() const; QString getTrackTotal() const; @@ -215,18 +188,13 @@ class Track : public QObject { return getPlayCounter().getTimesPlayed(); } - // Returns rating int getRating() const; - // Sets rating void setRating(int); - /// Resets the rating void resetRating() { setRating(mixxx::TrackRecord::kNoRating); } - // Get URL for track QString getURL() const; - // Set URL for track void setURL(const QString& url); /// Separator between artist and title string that is @@ -494,7 +462,7 @@ class Track : public QObject { // Storage for the track's beats mixxx::BeatsPointer m_pBeats; - //Visual waveform data + // Visual waveform data ConstWaveformPointer m_waveform; ConstWaveformPointer m_waveformSummary; From 2b8c1e3ae1953a89679f71325e4b2f3a7a8e1318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 7 Feb 2023 07:58:00 +0100 Subject: [PATCH 47/75] Describe the content of the track year property --- src/track/track.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/track/track.h b/src/track/track.h index c85aa50e11a..dcea22edacb 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -154,6 +154,11 @@ class Track : public QObject { QString getAlbumArtist() const; void setAlbumArtist(const QString&); + // Returns the content of the year library column. + // This was original only the four digit (gregorian) calendar year of the release date + // but allows to store any user string. Now it is altenatively used as + // recording date/time in the ISO 8601 yyyy-MM-ddTHH:mm:ss format tunkated at any point, + // following the TDRC ID3v2.4 frame or if not exists, TYER + TDAT. QString getYear() const; void setYear(const QString&); From cf381d38cfac5f72d1315a9b5afb08238ff5972f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 8 Feb 2023 22:12:37 +0100 Subject: [PATCH 48/75] Allow any numbers of leading zeros in Lancelot format. Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- src/track/keyutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/track/keyutils.cpp b/src/track/keyutils.cpp index 1e293230596..a3c90b1599b 100644 --- a/src/track/keyutils.cpp +++ b/src/track/keyutils.cpp @@ -17,7 +17,7 @@ using mixxx::track::io::key::ChromaticKey_IsValid; static const QString s_openKeyPattern("^\\s*(1[0-2]|[1-9])([dm])\\s*$"); // Lancelot notation, the numbers 1-12 followed by a (minor) or b (major). -static const QString s_lancelotKeyPattern("^\\s*(1[0-2]|0?[1-9])([ab])\\s*$"); +static const QString s_lancelotKeyPattern("^\\s*0*(1[0-2]|[1-9])([ab])\\s*$"); // a-g followed by any number of sharps or flats, optionally followed by // a scale spec (m = minor, min, maj) From 3bd8cd91bcc30023fa35cb1192bd3995f595d82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 8 Feb 2023 22:25:35 +0100 Subject: [PATCH 49/75] Explain RapidEvolution Key Code format --- src/track/keyutils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/track/keyutils.cpp b/src/track/keyutils.cpp index a3c90b1599b..5d3b0004e4d 100644 --- a/src/track/keyutils.cpp +++ b/src/track/keyutils.cpp @@ -17,6 +17,7 @@ using mixxx::track::io::key::ChromaticKey_IsValid; static const QString s_openKeyPattern("^\\s*(1[0-2]|[1-9])([dm])\\s*$"); // Lancelot notation, the numbers 1-12 followed by a (minor) or b (major). +// This is also used to detect RapidEvolution Key Code format using a padding "0" static const QString s_lancelotKeyPattern("^\\s*0*(1[0-2]|[1-9])([ab])\\s*$"); // a-g followed by any number of sharps or flats, optionally followed by From 48323076989692add452e21357d337eda88b9938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 8 Feb 2023 22:26:21 +0100 Subject: [PATCH 50/75] Use more const in guessKeyFromText() --- src/track/keyutils.cpp | 8 +++----- src/track/keyutils.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/track/keyutils.cpp b/src/track/keyutils.cpp index 5d3b0004e4d..47083e625fe 100644 --- a/src/track/keyutils.cpp +++ b/src/track/keyutils.cpp @@ -248,16 +248,14 @@ QString KeyUtils::getGlobalKeyText(const Keys& keys, KeyNotation notation) { } // static -ChromaticKey KeyUtils::guessKeyFromText(QString text) { +ChromaticKey KeyUtils::guessKeyFromText(const QString& text) { // Remove Shift (Tuning) Information used by Rapid Evolution like: "A#m +50"; int shiftStart = text.indexOf('+'); if (shiftStart < 0) { shiftStart = text.indexOf('-'); } - if (shiftStart >= 0) { - text = text.left(shiftStart); - } - const QString trimmed = text.trimmed(); + const QString trimmed = + shiftStart >= 0 ? text.left(shiftStart).trimmed() : text.trimmed(); if (trimmed.isEmpty()) { return mixxx::track::io::key::INVALID; diff --git a/src/track/keyutils.h b/src/track/keyutils.h index 7e5b8751d3c..5ac8d19dc0a 100644 --- a/src/track/keyutils.h +++ b/src/track/keyutils.h @@ -76,7 +76,7 @@ class KeyUtils { static QList getCompatibleKeys( mixxx::track::io::key::ChromaticKey key); - static mixxx::track::io::key::ChromaticKey guessKeyFromText(QString text); + static mixxx::track::io::key::ChromaticKey guessKeyFromText(const QString& text); static mixxx::track::io::key::ChromaticKey calculateGlobalKey( const KeyChangeList& key_changes, int iTotalSamples, int iSampleRate); From 36b8b4264dc3d869561fdea3b513d1c629ca8f94 Mon Sep 17 00:00:00 2001 From: holopansel Date: Thu, 9 Feb 2023 21:48:12 +0100 Subject: [PATCH 51/75] update with suggestions from JoergAtGithub --- res/controllers/Denon-MC7000-scripts.js | 685 ++++++++++++------------ 1 file changed, 341 insertions(+), 344 deletions(-) mode change 100644 => 100755 res/controllers/Denon-MC7000-scripts.js diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js old mode 100644 new mode 100755 index 39f0068ec9d..1411bac7925 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -49,6 +49,9 @@ MC7000.needleSearchPlay = false; // false: all triggered samplers will play simultaneously MC7000.prevSamplerStop = true; +// Quantity of Samplers used in mixxx possible values 16 and 32 +MC7000.SamplerQty = 16; + // 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). @@ -88,6 +91,7 @@ MC7000.scratchParams = { // set to 3 with audio buffer set to 5ms MC7000.jogSensitivity = 1; + /*///////////////////////////////// // USER VARIABLES END // /////////////////////////////////*/ @@ -149,9 +153,6 @@ MC7000.prevVuLevel = [0, 0, 0, 0]; MC7000.prevJogLED = [0, 0, 0, 0]; MC7000.prevPadLED = [0, 0, 0, 0]; -// Quantity of Samplers used in mixxx possible values 16 and 32 -MC7000.SamplerQty = 32; - // Param Buttons for Pitch Play MC7000.paramButton = [0, 0, 0, 0]; @@ -202,8 +203,6 @@ MC7000.padColor = { /* DECK INITIALIZATION */ MC7000.init = function() { - var i; - // obtain all knob and slider positions var ControllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7]; midi.sendSysexMsg(ControllerStatusSysex, ControllerStatusSysex.length); @@ -237,34 +236,34 @@ MC7000.init = function() { midi.sendShortMsg(0x93, 0x07, MC7000.isVinylMode ? 0x7F: 0x01); // HotCue Mode LEDs - for (i = 1; i <= 8; i++) { - engine.makeConnection("[Channel1]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel2]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel3]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel4]", "hotcue_"+i+"_enabled", MC7000.HotCueLED); + for (var cueIdx = 1; cueIdx <= 8; cueIdx++) { + engine.makeConnection("[Channel1]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); + engine.makeConnection("[Channel2]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); + engine.makeConnection("[Channel3]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); + engine.makeConnection("[Channel4]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); } // Sampler Mode LEDs - for (i = 1; i <= MC7000.SamplerQty; i++) { - engine.makeConnection("[Sampler"+i+"]", "track_loaded", MC7000.SamplerLED); - engine.makeConnection("[Sampler"+i+"]", "play", MC7000.SamplerLED); + for (var samplerIdx = 1; samplerIdx <= MC7000.SamplerQty; samplerIdx++) { + engine.makeConnection("[Sampler"+samplerIdx+"]", "track_loaded", MC7000.SamplerLED); + engine.makeConnection("[Sampler"+samplerIdx+"]", "play", MC7000.SamplerLED); } - // Sampler and Velocity Sampler Mode LEDs - for (i = 1; i <= MC7000.SamplerQty; i++) { - engine.makeConnection("[Sampler"+i+"]", "track_loaded", MC7000.VelSampLED); - engine.makeConnection("[Sampler"+i+"]", "play", MC7000.VelSampLED); + // Velocity Sampler Mode LEDs + for (var velSampIdx = 1; velSampIdx <= MC7000.SamplerQty; velSampIdx++) { + engine.makeConnection("[Sampler"+velSampIdx+"]", "track_loaded", MC7000.VelSampLED); + engine.makeConnection("[Sampler"+velSampIdx+"]", "play", MC7000.VelSampLED); } //Pitch LEDs - for (i = 1; i <= 8; i++) { - engine.makeConnection("[Channel1]", "hotcue_"+i+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel2]", "hotcue_"+i+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel3]", "hotcue_"+i+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel4]", "hotcue_"+i+"_enabled", MC7000.PitchLED); + for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { + engine.makeConnection("[Channel1]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel2]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel3]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Channel4]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); } // 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); + for (var chanIdx = 1; chanIdx <= 4; chanIdx++) { + engine.softTakeover("[Channel" + chanIdx + "]", "rate", true); } }, true); }; @@ -286,249 +285,227 @@ MC7000.samplerLevel = function(channel, control, value) { // PAD Mode Hot Cue MC7000.padModeCue = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = true; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = true; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Hot Cue Mode for (var i = 1; i <= 8; i++) { var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } }; // PAD Mode Cue Loop MC7000.padModeCueLoop = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = true; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = true; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Flip MC7000.padModeFlip = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = true; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = true; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Roll MC7000.padModeRoll = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = true; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = true; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Roll Mode - MC7000.setPadColor(deckOffset, MC7000.padColor.rolloff); + MC7000.setPadColor(deckIndex, MC7000.padColor.rolloff); }; // PAD Mode Saved Loop MC7000.padModeSavedLoop = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = true; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = true; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Saved Loop Mode for (var i = 0; i < 8; i++) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, activeLED); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, activeLED); } }; // PAD Mode Slicer MC7000.padModeSlicer = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = true; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = true; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Slicer Mode - MC7000.setPadColor(deckOffset, MC7000.padColor.sliceron); + MC7000.setPadColor(deckIndex, MC7000.padColor.sliceron); }; // PAD Mode Slicer Loop MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = true; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = true; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckOffset, MC7000.padColor.alloff); + MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Sampler MC7000.padModeSampler = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = true; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = true; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Sampler Mode - var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; - var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; - for (var i = 1; i <= 8; i++) { - var samplerOffset = samplerUnitOffset + i; - if (engine.getValue("[Sampler" + samplerOffset + "]", "play")) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); - } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.sampleroff); - } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerloaded); - } - } + MC7000.SamplerLED(); }; // PAD Mode Velocity Sampler MC7000.padModeVelSamp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = true; - MC7000.PADModePitch[deckOffset] = false; + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = true; + MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Velocity Sampler Mode - var samplersShouldWrap = MC7000.SamplerQty === 16 && deckOffset >= 2; - var samplerUnitOffset = (samplersShouldWrap ? deckOffset % 2 : deckOffset) * 8; - for (var i = 1; i <= 8; i++) { - var samplerOffset = samplerUnitOffset + i; - if (engine.getValue("[Sampler" + samplerOffset+ "]", "play")) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); - } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampoff); - } else if (engine.getValue("[Sampler" + samplerOffset+ "]", "track_loaded") === 1) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsamploaded); - } - } + MC7000.VelSampLED(); }; // PAD Mode Pitch MC7000.HotcueSelectedGroup = [0, 0, 0, 0]; MC7000.padModePitch = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { return; // don't respond to note off messages } - MC7000.halftoneToPadMap[deckOffset] = [4, 5, 6, 7, 0, 1, 2, 3]; - - MC7000.PADModeCue[deckOffset] = false; - MC7000.PADModeCueLoop[deckOffset] = false; - MC7000.PADModeFlip[deckOffset] = false; - MC7000.PADModeRoll[deckOffset] = false; - MC7000.PADModeSavedLoop[deckOffset] = false; - MC7000.PADModeSlicer[deckOffset] = false; - MC7000.PADModeSlicerLoop[deckOffset] = false; - MC7000.PADModeSampler[deckOffset] = false; - MC7000.PADModeVelSamp[deckOffset] = false; - MC7000.PADModePitch[deckOffset] = true; + MC7000.halftoneToPadMap[deckIndex] = [4, 5, 6, 7, 0, 1, 2, 3]; + + MC7000.PADModeCue[deckIndex] = false; + MC7000.PADModeCueLoop[deckIndex] = false; + MC7000.PADModeFlip[deckIndex] = false; + MC7000.PADModeRoll[deckIndex] = false; + MC7000.PADModeSavedLoop[deckIndex] = false; + MC7000.PADModeSlicer[deckIndex] = false; + MC7000.PADModeSlicerLoop[deckIndex] = false; + MC7000.PADModeSampler[deckIndex] = false; + MC7000.PADModeVelSamp[deckIndex] = false; + MC7000.PADModePitch[deckIndex] = true; // switch on initial PAD illumination = hotcue for pitch or if // MC7000.HotcueSelectedGroup selected = pad mode pitchoff color for (var i = 1; i <= 8; i++) { - if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); + if (MC7000.HotcueSelectedGroup[deckIndex] !== 0) { + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.pitchoff); } else { var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } } }; @@ -537,7 +514,7 @@ MC7000.padModePitch = function(channel, control, value, status, group) { // PAD buttons MC7000.PadButtons = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; var i, j, z; // The following modes are currently unhandled and could be @@ -548,7 +525,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { // - MC7000.PADModeSlicerLoop // activate and clear Hot Cues - if (MC7000.PADModeCue[deckOffset] && engine.getValue(group, "track_loaded") === 1) { + if (MC7000.PADModeCue[deckIndex] && engine.getValue(group, "track_loaded") === 1) { for (i = 1; i <= 8; i++) { if (control === 0x14 + i - 1 && value === 0x7F) { engine.setValue(group, "hotcue_" + i + "_activate", true); @@ -562,20 +539,20 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } 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); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueoff); } } - } else if (MC7000.PADModeRoll[deckOffset]) { + } else if (MC7000.PADModeRoll[deckIndex]) { // TODO(all): check for actual beatloop_size and apply back after a PAD Roll i = control - 0x14; if (control === 0x14 + i && value > 0x00) { engine.setValue(group, "beatlooproll_" + MC7000.beatLoopRoll[i] + "_activate", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.rollon); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, MC7000.padColor.rollon); } else if (control === 0x14 + i && value === 0x00) { engine.setValue(group, "beatlooproll_activate", false); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.rolloff); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, MC7000.padColor.rolloff); } - } else if (MC7000.PADModeSavedLoop[deckOffset]) { + } else if (MC7000.PADModeSavedLoop[deckIndex]) { if (value === 0x00) { return; // don't respond to note off messages } @@ -583,152 +560,144 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_toggle", true); for (j = 0; j < 8; j++) { var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[j] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; - midi.sendShortMsg(0x94 + deckOffset, 0x14 + j, activeLED); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + j, activeLED); } - } else if (MC7000.PADModeSlicer[deckOffset]) { + } else if (MC7000.PADModeSlicer[deckIndex]) { if (value > 0) { i = control - 0x14; // unshifted button j = control - 0x1C; // shifted button // forward buttons (PAD buttons upper row) if (control >= 0x14 && control <= 0x17) { engine.setValue(group, "beatjump_" + MC7000.beatJump[i] + "_forward", true); - midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.slicerJumpFwd); // backward buttons (PAD buttons lower row) } else if (control >= 0x18 && control <= 0x1B) { engine.setValue(group, "beatjump_" + MC7000.beatJump[i - 4] + "_backward", true); - midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.slicerJumpBack); + midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.slicerJumpBack); // forward buttons (PAD buttons upper row - shifted controls) } else if (control >= 0x1C && control <= 0x1F) { engine.setValue(group, "beatjump_" + MC7000.beatJump[j + 4] + "_forward", true); - midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.slicerJumpFwd); // backward buttons (PAD buttons lower row - shifted controls) } else if (control >= 0x20 && control <= 0x23) { engine.setValue(group, "beatjump_" + MC7000.beatJump[j] + "_backward", true); - midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.slicerJumpBack); + midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.slicerJumpBack); } } else { - midi.sendShortMsg(0x94 + deckOffset, control, MC7000.padColor.sliceron); + midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.sliceron); } - } else if (MC7000.PADModeSampler[deckOffset]) { + } else if (MC7000.PADModeSampler[deckIndex]) { var samplerOffset = 0; var samplerOffsetJ = 0; - for (i = 1; i <= 8; i++) { + var deckOffset = 0; + for (var samplerIdx = 1; samplerIdx <= 8; samplerIdx++) { if (MC7000.SamplerQty === 16) { - if (deckOffset >= 2) { - deckOffset = deckOffset - 2; - } + deckOffset = (deckIndex % 2) * 8; + } else if (MC7000.SamplerQty === 32) { + deckOffset = deckIndex * 8; } - samplerOffset = deckOffset * 8 + i; - if (control === 0x14 + i - 1 && value >= 0x01) { + samplerOffset = deckOffset + samplerIdx; + if (control === 0x14 + samplerIdx - 1 && value >= 0x01) { if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerloaded); + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck for (j = 1; j <= 8; j++) { - samplerOffsetJ = deckOffset * 8 + j; + samplerOffsetJ = deckOffset + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + j - 1, MC7000.padColor.samplerloaded); + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + j - 1, MC7000.padColor.samplerloaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.samplerplay); - } - } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler - if (MC7000.SamplerQty === 16) { - if ((deckOffset) >= 2) { - deckOffset = deckOffset + 2; - } + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); } + } else if (control === 0x1C + samplerIdx - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandstop", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.samplerloaded); } else { engine.setValue("[Sampler" + samplerOffset + "]", "eject", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.sampleroff); engine.setValue("[Sampler" + samplerOffset + "]", "eject", 0); } } + MC7000.SamplerLED(); } - } else if (MC7000.PADModeVelSamp[deckOffset]) { + } else if (MC7000.PADModeVelSamp[deckIndex]) { samplerOffset = 0; samplerOffsetJ = 0; - for (i = 1; i <= 8; i++) { + deckOffset = 0; + for (var velSampIdx = 1; velSampIdx <= 8; velSampIdx++) { if (MC7000.SamplerQty === 16) { - if (deckOffset >= 2) { - deckOffset = deckOffset - 2; - } + deckOffset = (deckIndex % 2) * 8; + } else if (MC7000.SamplerQty === 32) { + deckOffset = deckIndex * 8; } - samplerOffset = deckOffset * 8 + i; - if (control === 0x14 + i - 1 && value >= 0x01) { + samplerOffset = deckOffset + velSampIdx; + if (control === 0x14 + velSampIdx - 1 && value >= 0x01) { // if padbutton for sampler VelSampIdx pressed if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { // if sampler is not loaded, load sampler and set color to loaded engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsamploaded); + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck for (j = 1; j <= 8; j++) { - samplerOffsetJ = deckOffset * 8 + j; + samplerOffsetJ = deckOffset + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + j - 1, MC7000.padColor.velsamploaded); + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + j - 1, MC7000.padColor.velsamploaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", script.absoluteNonLin(value, 0, 1.0, 4.0)); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.velsampplay); + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); } - } else if (control === 0x1C + i - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler + } else if (control === 0x1C + velSampIdx - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); - if (MC7000.SamplerQty === 16) { - if ((deckOffset) >= 2) { - deckOffset = deckOffset + 2; - } - } if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandstop", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.velsamploaded); + // midi.sendShortMsg(0x94 + deckIndex, 0x1C + velSampIdx - 1, MC7000.padColor.velsamploaded); } else { engine.setValue("[Sampler" + samplerOffset + "]", "eject", 1); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.velsampoff); + // midi.sendShortMsg(0x94 + deckIndex, 0x1C + velSampIdx - 1, MC7000.padColor.velsampoff); engine.setValue("[Sampler" + samplerOffset + "]", "eject", 0); } } + MC7000.VelSampLED(); } - } else if (MC7000.PADModePitch[deckOffset]) { // TODO TODO play and cue dependency to play and cue button + } else if (MC7000.PADModePitch[deckIndex]) { // TODO play and cue dependency to play and cue button if (engine.getValue(group, "track_loaded") === 1) { - for (i = 1; i <= 8; i++) { + for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { // intermediate variables var isButtonPressed = (value === 0x7F); var isButtonReleased = (value === 0x00); - var isControlAddress = (control === 0x14 + i -1); - var isControlAddressShift = (control === 0x1C + i -1); - var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckOffset]; + var isControlAddress = (control === 0x14 + pitchIdx - 1); + var isControlAddressShift = (control === 0x1C + pitchIdx - 1); + var hotcueEnabled = engine.getValue(group, "hotcue_" + pitchIdx + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckIndex]; if (isButtonPressed && isControlAddress) { if (!HotcueSelectedOnDeck) { - MC7000.setPadColor(deckOffset, MC7000.padColor.pitchoff); - MC7000.HotcueSelectedGroup[deckOffset] = i; // store which hotcue should be used for pitch + MC7000.setPadColor(deckIndex, MC7000.padColor.pitchoff); + MC7000.HotcueSelectedGroup[deckIndex] = pitchIdx; // store which hotcue should be used for pitch if (!hotcueEnabled) { //hotcue select if none available - engine.setValue(group, "hotcue_" + i + "_activate", true); // set hotcue if not set before + engine.setValue(group, "hotcue_" + pitchIdx + "_activate", true); // set hotcue if not set before } } else { // hotcue selected and button pressed // TODO: play if play, stop if cue - engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop - MC7000.setPadColor(deckOffset, MC7000.padColor.pitchoff); - engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckOffset][i-1]); - engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandplay", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.pitchon); // keep color when shift is pressed + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckIndex] + "_gotoandstop", true); // stop + MC7000.setPadColor(deckIndex, MC7000.padColor.pitchoff); + engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckIndex][pitchIdx - 1]); + engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckIndex] + "_gotoandplay", true); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color + midi.sendShortMsg(0x94 + deckIndex, 0x1C + pitchIdx - 1, MC7000.padColor.pitchon); // keep color when shift is pressed } } else if (isButtonReleased && isControlAddress) { // button release change color and stop play - // engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckOffset] + "_gotoandstop", true); // stop //TODO if for setting continue to play or stop on button release - // midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.pitchoff); // switch to pitch off color + // engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckIndex] + "_gotoandstop", true); // stop //TODO if for setting continue to play or stop on button release + // midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx - 1, MC7000.padColor.pitchoff); // switch to pitch off color if (engine.getValue(group, "slip_enabled")) { engine.setValue(group, "slip_enabled", false); engine.beginTimer(50, function() { @@ -737,11 +706,11 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } } else if (isButtonPressed && isControlAddressShift) { //shifted buttons deselect hotcue for pitch engine.setValue(group, "pitch", 0); - MC7000.HotcueSelectedGroup[deckOffset] = 0; + MC7000.HotcueSelectedGroup[deckIndex] = 0; for (z = 1; z <= 8; z++) { hotcueEnabled = engine.getValue(group, "hotcue_" + z + "_enabled", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed + midi.sendShortMsg(0x94 + deckIndex, 0x14 + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed } } } @@ -750,20 +719,20 @@ MC7000.PadButtons = function(channel, control, value, status, group) { }; -MC7000.setPadColor = function(deckOffset, colorValue) { +MC7000.setPadColor = function(deckIndex, colorValue) { for (var z = 0; z < 8; z++) { // switch 8 buttons to selected color - midi.sendShortMsg(0x94 + deckOffset, 0x14 + z, colorValue); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + z, colorValue); // keep color when shift is pressed + midi.sendShortMsg(0x94 + deckIndex, 0x14 + z, colorValue); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + z, colorValue); // keep color when shift is pressed } }; // Shift Button MC7000.shiftButton = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; - MC7000.shift[deckOffset] = value > 0; - midi.sendShortMsg(0x90 + deckOffset, 0x32, - MC7000.shift[deckOffset] ? 0x7F : 0x01); + var deckIndex = script.deckFromGroup(group) - 1; + MC7000.shift[deckIndex] = value > 0; + midi.sendShortMsg(0x90 + deckIndex, 0x32, + MC7000.shift[deckIndex] ? 0x7F : 0x01); }; // Toggle Vinyl Mode @@ -771,10 +740,10 @@ MC7000.vinylModeToggle = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - var deckOffset = script.deckFromGroup(group) - 1; - MC7000.isVinylMode[deckOffset] = !MC7000.isVinylMode[deckOffset]; - midi.sendShortMsg(0x90 + deckOffset, 0x07, - MC7000.isVinylMode[deckOffset] ? 0x7F : 0x01); + var deckIndex = script.deckFromGroup(group) - 1; + MC7000.isVinylMode[deckIndex] = !MC7000.isVinylMode[deckIndex]; + midi.sendShortMsg(0x90 + deckIndex, 0x07, + MC7000.isVinylMode[deckIndex] ? 0x7F : 0x01); }; // Use select button to load and eject track from deck @@ -815,9 +784,9 @@ MC7000.loadButton = function(channel, control, value, status, group) { // The button that enables/disables scratching MC7000.wheelTouch = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; var libraryMaximized = engine.getValue("[Master]", "maximize_library") > 0; - if (MC7000.isVinylMode[deckOffset] && !libraryMaximized) { + if (MC7000.isVinylMode[deckIndex] && !libraryMaximized) { if (value === 0x7F) { engine.scratchEnable(deckNumber, MC7000.jogWheelTicksPerRevolution, MC7000.scratchParams.recordSpeed, @@ -846,7 +815,7 @@ MC7000.wheelTurn = function(channel, control, value, status, group) { var numTicks = (value < 0x64) ? value : (value - 128); var adjustedSpeed = numTicks * MC7000.jogSensitivity / 10; var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; var libraryMaximized = engine.getValue("[Master]", "maximize_library"); if (libraryMaximized === 1 && numTicks > 0) { engine.setValue("[Library]", "MoveDown", 1); @@ -856,7 +825,7 @@ MC7000.wheelTurn = function(channel, control, value, status, group) { // Scratch! engine.scratchTick(deckNumber, numTicks * MC7000.jogSensitivity); } else { - if (MC7000.shift[deckOffset]) { + if (MC7000.shift[deckIndex]) { // While Shift Button pressed -> Search through track var jogSearch = 100 * adjustedSpeed; // moves 100 times faster than normal jog engine.setValue(group, "jog", jogSearch); @@ -869,19 +838,19 @@ MC7000.wheelTurn = function(channel, control, value, status, group) { // Needle Search Touch detection MC7000.needleSearchTouch = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; + var deckIndex = script.deckFromGroup(group) - 1; if (engine.getValue(group, "play")) { - MC7000.needleSearchTouched[deckOffset] = MC7000.needleSearchPlay && (!!value); + MC7000.needleSearchTouched[deckIndex] = MC7000.needleSearchPlay && (!!value); } else { - MC7000.needleSearchTouched[deckOffset] = !!value; + MC7000.needleSearchTouched[deckIndex] = !!value; } }; // Needle Search Touch while "SHIFT" button is pressed MC7000.needleSearchTouchShift = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; - MC7000.needleSearchTouched[deckOffset] = !!value; + var deckIndex = script.deckFromGroup(group) - 1; + MC7000.needleSearchTouched[deckIndex] = !!value; }; // Needle Search Position detection (MSB) @@ -892,8 +861,8 @@ MC7000.needleSearchMSB = function(channel, control, value) { // Needle Search Position detection (MSB + LSB) MC7000.needleSearchStripPosition = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; - if (MC7000.needleSearchTouched[deckOffset]) { + var deckIndex = script.deckFromGroup(group) - 1; + if (MC7000.needleSearchTouched[deckIndex]) { var fullValue = (MC7000.needleDropMSB << 7) + value; // move MSB 7 binary digits to the left and add LSB var position = (fullValue / 0x3FFF); // divide by all possible positions to get relative between 0 - 1 engine.setParameter(group, "playposition", position); @@ -950,9 +919,9 @@ MC7000.getPrevRateRange = function(currRateRange) { // Key & Waveform zoom Select MC7000.keySelect = function(midichan, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; + var deckIndex = script.deckFromGroup(group) - 1; // While Shift Button is pressed: Waveform Zoom - if (MC7000.shift[deckOffset]) { + if (MC7000.shift[deckIndex]) { if (value === 0x7F) { script.triggerControl(group, "waveform_zoom_up", 100); } else { @@ -970,12 +939,12 @@ MC7000.keySelect = function(midichan, control, value, status, group) { // Key & Waveform zoom Reset MC7000.keyReset = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; + var deckIndex = script.deckFromGroup(group) - 1; if (value === 0x00) { return; } // While Shift Button is pressed: Waveform Zoom Reset - if (MC7000.shift[deckOffset]) { + if (MC7000.shift[deckIndex]) { script.triggerControl(group, "waveform_zoom_set_default", 100); // While Shift Button is released: Key Reset } else { @@ -996,12 +965,12 @@ MC7000.crossfaderAssign = function(channel, control, value, status, group) { // Assign Spinback length to STOP TIME knob MC7000.stopTime = function(channel, control, value, status, group) { - var deckOffset = script.deckFromGroup(group) - 1; + var deckIndex = script.deckFromGroup(group) - 1; // "factor" for engine.brake() and engine.softStart() // this formula produces factors between 31 (min STOP TIME for ca 7 sec back // in track) and 1 (max STOP TIME for ca 18.0 sec back in track) - MC7000.factor[deckOffset] = (1.1 - (value / 127)) * 30 - 2; - MC7000.factor2[deckOffset] = (127.69 - value); + MC7000.factor[deckIndex] = (1.1 - (value / 127)) * 30 - 2; + MC7000.factor2[deckIndex] = (127.69 - value); }; MC7000.lastpress = [0, 0, 0, 0]; @@ -1010,24 +979,24 @@ MC7000.play = function(channel, control, value, status, group) { return; // don't respond to note off messages } var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; // set a variable to toggle between play and pause, based on current play status var playToggle = engine.getValue(group, "play"); - if (MC7000.factor[deckOffset] === 31) { // factor 31 means stop time knob is at zero position + if (MC7000.factor[deckIndex] === 31) { // factor 31 means stop time knob is at zero position engine.setValue(group, "play", !playToggle); - MC7000.lastpress[deckOffset] = 0; + MC7000.lastpress[deckIndex] = 0; } else { if (playToggle) { - if (!MC7000.lastpress[deckOffset]) { - engine.brake(deckNumber, true, MC7000.factor2[deckOffset]); - MC7000.lastpress[deckOffset] = 1; + if (!MC7000.lastpress[deckIndex]) { + engine.brake(deckNumber, true, MC7000.factor2[deckIndex]); + MC7000.lastpress[deckIndex] = 1; } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckOffset]); - MC7000.lastpress[deckOffset] = 0; + engine.softStart(deckNumber, true, MC7000.factor2[deckIndex]); + MC7000.lastpress[deckIndex] = 0; } } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckOffset]); - MC7000.lastpress[deckOffset] = 0; + engine.softStart(deckNumber, true, MC7000.factor2[deckIndex]); + MC7000.lastpress[deckIndex] = 0; } } }; @@ -1035,11 +1004,11 @@ MC7000.play = function(channel, control, value, status, group) { // Use SHIFT + CENSOR button as Spinback with STOP TIME adjusted length MC7000.reverse = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value > 0) { // while the button is pressed spin back // start at a rate of -10 and decrease by "MC7000.factor" - engine.brake(deckNumber, true, MC7000.factor[deckOffset], -10); + engine.brake(deckNumber, true, MC7000.factor[deckIndex], -10); } else { if (engine.getValue(group, "slip_enabled")) { engine.brake(deckNumber, false); // disable brake effect @@ -1049,7 +1018,7 @@ MC7000.reverse = function(channel, control, value, status, group) { engine.setValue(group, "slip_enabled", true); }, true); } else { - engine.softStart(deckNumber, true, MC7000.factor[deckOffset]); + engine.softStart(deckNumber, true, MC7000.factor[deckIndex]); } } }; @@ -1079,13 +1048,13 @@ MC7000.censor = function(channel, control, value, status, group) { // Param Button for Pitch Play to increase or decrease pitch, Star rating otherwise MC7000.StarsDown = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { //return; // don't respond to note off messages } else { - if (MC7000.PADModePitch[deckOffset]) { + if (MC7000.PADModePitch[deckIndex]) { for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckOffset][i] = MC7000.halftoneToPadMap[deckOffset][i] - 8; // pitch down + MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] - 8; // pitch down } } else { engine.setValue(group, "stars_down", true); // stars down @@ -1095,13 +1064,13 @@ MC7000.StarsDown = function(channel, control, value, status, group) { MC7000.StarsUp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; if (value === 0x00) { //return; // don't respond to note off messages } else { - if (MC7000.PADModePitch[deckOffset]) { + if (MC7000.PADModePitch[deckIndex]) { for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckOffset][i] = MC7000.halftoneToPadMap[deckOffset][i] + 8; // pitch up + MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] + 8; // pitch up } } else { engine.setValue(group, "stars_up", true); // stars up @@ -1116,10 +1085,10 @@ MC7000.crossFaderCurve = function(control, value) { // Update state on deck changes MC7000.switchDeck = function(channel, control, value, status) { - var deckOffset = status - 0x90; - var isTopDeck = deckOffset < 2; - var side = deckOffset % 2; - var previousDeckOffset = (deckOffset + 2) % 4; + var deckIndex = status - 0x90; + var isTopDeck = deckIndex < 2; + var side = deckIndex % 2; + var previousdeckIndex = (deckIndex + 2) % 4; // We need to 'transfer' the shift state when switching decks, // otherwise it will get stuck and result in an 'inverted' @@ -1129,8 +1098,8 @@ MC7000.switchDeck = function(channel, control, value, status) { if (value === 0x7F && MC7000.topDeckActive[side] !== isTopDeck) { MC7000.topDeckActive[side] = isTopDeck; - MC7000.shift[deckOffset] = MC7000.shift[previousDeckOffset]; - MC7000.shift[previousDeckOffset] = false; + MC7000.shift[deckIndex] = MC7000.shift[previousdeckIndex]; + MC7000.shift[previousdeckIndex] = false; } }; @@ -1167,13 +1136,13 @@ MC7000.sortLibrary = function(channel, control, value) { /* LEDs for VuMeter */ // VuMeters only for Channel 1-4 / Master is on Hardware MC7000.VuMeter = function(value, group) { - var deckOffset = script.deckFromGroup(group) - 1; + var deckIndex = script.deckFromGroup(group) - 1; // sends either PeakIndicator or scales value (0..1) to (0..117) while truncating to each LED var vuLevelOutValue = engine.getValue(group, "PeakIndicator") ? MC7000.VuMeterLEDPeakValue : Math.floor(Math.pow(value, 2.5) * 9) * 13; // only send Midi signal when LED value has changed - if (MC7000.prevVuLevel[deckOffset] !== vuLevelOutValue) { - midi.sendShortMsg(0xB0 + deckOffset, 0x1F, vuLevelOutValue); - MC7000.prevVuLevel[deckOffset] = vuLevelOutValue; + if (MC7000.prevVuLevel[deckIndex] !== vuLevelOutValue) { + midi.sendShortMsg(0xB0 + deckIndex, 0x1F, vuLevelOutValue); + MC7000.prevVuLevel[deckIndex] = vuLevelOutValue; } }; @@ -1187,7 +1156,7 @@ MC7000.TrackPositionLEDs = function(value, group) { } // lets define some variables first var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; + var deckIndex = deckNumber - 1; var trackDuration = engine.getValue(group, "duration"); // in seconds var beatLength = engine.getValue(group, "file_bpm") / 60; // in Beats Per Seconds var cuePosition = engine.getValue(group, "cue_point") / engine.getValue(group, "track_samplerate") / 2; // in seconds @@ -1195,58 +1164,58 @@ MC7000.TrackPositionLEDs = function(value, group) { var jogLEDPosition = playPosition / 60 * MC7000.scratchParams.recordSpeed; var jogLEDNumber = 48; // LED ring contains 48 segments each triggered by the next even Midi value // check for Vinyl Mode and decide to spin the Jog LED or show play position - var activeJogLED = MC7000.isVinylMode[deckOffset] ? Math.round(jogLEDPosition * jogLEDNumber) % jogLEDNumber : Math.round(value * jogLEDNumber); + var activeJogLED = MC7000.isVinylMode[deckIndex] ? Math.round(jogLEDPosition * jogLEDNumber) % jogLEDNumber : Math.round(value * jogLEDNumber); // count the beats (1 to 8) after the CUE point var beatCountLED = (Math.floor((playPosition - cuePosition) * beatLength) % 8); //calculate PAD LED position // TODO(all): check for playposition < (trackduration - warning length) for sending position signals // check if a Jog LED has changed and if so then send the signal to the next Jog LED - if (MC7000.prevJogLED[deckOffset] !== activeJogLED) { - midi.sendShortMsg(0x90 + deckOffset, 0x06, activeJogLED * 2); // only each 2nd midi signal triggers the next LED - MC7000.prevJogLED[deckOffset] = activeJogLED; + if (MC7000.prevJogLED[deckIndex] !== activeJogLED) { + midi.sendShortMsg(0x90 + deckIndex, 0x06, activeJogLED * 2); // only each 2nd midi signal triggers the next LED + MC7000.prevJogLED[deckIndex] = activeJogLED; } // TODO(all): else blink the platter LEDs // check if Slicer mode is active and illuminate PAD LEDs counting with the beat while playing if (!MC7000.experimental) { return; } - if (MC7000.PADModeSlicer[deckOffset]) { + if (MC7000.PADModeSlicer[deckIndex]) { // only send new LED status when beatCountLED really changes - if (MC7000.prevPadLED[deckOffset] !== beatCountLED) { + if (MC7000.prevPadLED[deckIndex] !== beatCountLED) { // first set all LEDs to default color incl shifted for (var i = 0; i < 16; i++) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.sliceron); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, MC7000.padColor.sliceron); } // now chose which PAD LED to turn on (+8 means shifted PAD LEDs) if (beatCountLED === 0) { - midi.sendShortMsg(0x94 + deckOffset, 0x14, MC7000.padColor.slicerJumpFwd); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x14, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + 8, MC7000.padColor.slicerJumpFwd); } else if (beatCountLED === 7) { - midi.sendShortMsg(0x94 + deckOffset, 0x1B, MC7000.padColor.slicerJumpFwd); - midi.sendShortMsg(0x94 + deckOffset, 0x1B + 8, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x1B, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x1B + 8, MC7000.padColor.slicerJumpFwd); } else if (beatCountLED > 0 && beatCountLED < 7) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + beatCountLED, MC7000.padColor.slicerJumpFwd); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + 8 + beatCountLED, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + beatCountLED, MC7000.padColor.slicerJumpFwd); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + 8 + beatCountLED, MC7000.padColor.slicerJumpFwd); } } - MC7000.prevPadLED[deckOffset] = beatCountLED; + MC7000.prevPadLED[deckIndex] = beatCountLED; } }; // initial HotCue LED when loading a track with already existing hotcues MC7000.HotCueLED = function(value, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; - if (MC7000.PADModeCue[deckOffset]) { + var deckIndex = deckNumber - 1; + if (MC7000.PADModeCue[deckIndex]) { for (var i = 1; i <= 8; i++) { if (value === 1) { if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueon); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueon); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.hotcueon); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueon); } } else { if (engine.getValue(group, "hotcue_"+i+"_enabled") === 0) { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i - 1, MC7000.padColor.hotcueoff); - midi.sendShortMsg(0x94 + deckOffset, 0x1C + i - 1, MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueoff); } } } @@ -1255,19 +1224,36 @@ MC7000.HotCueLED = function(value, group) { // Sampler LED MC7000.SamplerLED = function() { - for (var j = 0; j < 4; j++) { - for (var i = 0; i < 8; i++) { + for (var deckIdx = 0; deckIdx < 4; deckIdx++) { + for (var samplerIdx = 1; samplerIdx <= 8; samplerIdx++) { var sampNo = 0; - if (MC7000.PADModeSampler[j]) { + if (MC7000.PADModeSampler[deckIdx]) { if (MC7000.SamplerQty === 16) { - (j >= 2) ? sampNo = (j - 2) * 8 + i + 1 : sampNo = j * 8 + i + 1; + sampNo = (deckIdx % 2) * 8 + samplerIdx; + var inactiveSamplerDeck = (deckIdx >= 2) ? deckIdx - 2 : deckIdx + 2; } else if (MC7000.SamplerQty === 32) { - sampNo = j * 8 + i + 1; + sampNo = deckIdx * 8 + samplerIdx; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { - (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) ? midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.samplerloaded) : midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.samplerplay); + if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { + midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); + // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.samplerloaded); //same color when shift is pressed + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); + } + } else { + midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); + // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.samplerplay); //same color when shift is pressed + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); + } + } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.sampleroff); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); + // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.sampleroff); //same color when shift is pressed + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); + } } } } @@ -1276,24 +1262,35 @@ MC7000.SamplerLED = function() { // Velocity Sampler LED MC7000.VelSampLED = function() { - for (var j = 0; j < 4; j++) { - for (var i = 0; i < 8; i++) { + for (var deckIdx = 0; deckIdx < 4; deckIdx++) { + for (var velSampIdx = 1; velSampIdx <= 8; velSampIdx++) { var sampNo = 0; - if (MC7000.PADModeVelSamp[j]) { + if (MC7000.PADModeVelSamp[deckIdx]) { if (MC7000.SamplerQty === 16) { - (j >= 2) ? sampNo = (j - 2) * 8 + i + 1: sampNo = j * 8 + i + 1; - } else { - sampNo = j * 8 + i + 1; + sampNo = (deckIdx % 2) * 8 + velSampIdx; + var inactiveVelSampDeck = (deckIdx >= 2) ? deckIdx - 2 : deckIdx + 2; + } else if (MC7000.SamplerQty === 32) { + sampNo = deckIdx * 8 + velSampIdx; // use sampler 1 - sampler 32 for deck 1 - 4 } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; if (samplerIsNotPlaying) { - midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.velsamploaded); engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); + engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); + } } else { - midi.sendShortMsg(0x94 + j, 0x14 + i - 1, MC7000.padColor.velsampplay); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); + } } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + j, 0x14 + i, MC7000.padColor.velsampoff); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); + if (MC7000.SamplerQty === 16) { + midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); + } } } } @@ -1303,18 +1300,18 @@ MC7000.VelSampLED = function() { // Pitch LED when loading a track with already existing hotcues for pitch MC7000.PitchLED = function(value, group) { var deckNumber = script.deckFromGroup(group); - var deckOffset = deckNumber - 1; - if (MC7000.PADModePitch[deckOffset]) { - for (var i = 0; i < 8; i++) { + var deckIndex = deckNumber - 1; + if (MC7000.PADModePitch[deckIndex]) { + for (var pitchIdx = 0; pitchIdx < 8; pitchIdx++) { if (engine.getValue("[Channel"+deckNumber+"]", "play") === 0) { // stopped - if (MC7000.HotcueSelectedGroup[deckOffset] !== 0) { // hotcue selected - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.pitchoff); + if (MC7000.HotcueSelectedGroup[deckIndex] !== 0) { // hotcue selected + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx, MC7000.padColor.pitchoff); } else { - var hotcueEnabled = engine.getValue(group, "hotcue_" + i + 1 + "_enabled", true); - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + var hotcueEnabled = engine.getValue(group, "hotcue_" + pitchIdx + 1 + "_enabled", true); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } } else { - midi.sendShortMsg(0x94 + deckOffset, 0x14 + i, MC7000.padColor.pitchon); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx, MC7000.padColor.pitchon); } } } From f4fc7a49d4e7e95daa656093b32b1ad89a4a1a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 9 Feb 2023 23:00:55 +0100 Subject: [PATCH 52/75] Explain the spaces in the tets data --- src/test/searchqueryparsertest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index 30152b5170c..eabed3172a4 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -391,6 +391,7 @@ TEST_F(SearchQueryParserTest, NumericFilterYear) { TrackPointer pTrack = newTestTrack(44100); EXPECT_FALSE(pQuery->match(pTrack)); + // Note: The sourounding spaces are checking that a user input is popperly trimmed. pTrack->setYear(" 1969-08-15 "); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setYear(" 19690815 "); From c1ee012db9eb1b35baadc69cecce3f2f526ba20f Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Feb 2023 16:03:08 +0100 Subject: [PATCH 53/75] coloring update and commented lines removed --- res/controllers/Denon-MC7000-scripts.js | 40 +++++-------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 1411bac7925..37d5b780027 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -600,7 +600,6 @@ MC7000.PadButtons = function(channel, control, value, status, group) { if (control === 0x14 + samplerIdx - 1 && value >= 0x01) { if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck @@ -608,14 +607,12 @@ MC7000.PadButtons = function(channel, control, value, status, group) { samplerOffsetJ = deckOffset + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + j - 1, MC7000.padColor.samplerloaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); } } else if (control === 0x1C + samplerIdx - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { @@ -641,7 +638,6 @@ MC7000.PadButtons = function(channel, control, value, status, group) { if (control === 0x14 + velSampIdx - 1 && value >= 0x01) { // if padbutton for sampler VelSampIdx pressed if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 0) { // if sampler is not loaded, load sampler and set color to loaded engine.setValue("[Sampler" + samplerOffset + "]", "LoadSelectedTrack", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck @@ -649,23 +645,19 @@ MC7000.PadButtons = function(channel, control, value, status, group) { samplerOffsetJ = deckOffset + j; if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + j - 1, MC7000.padColor.velsamploaded); } } } // ... before the actual sampler to play gets started engine.setValue("[Sampler" + samplerOffset + "]", "pregain", script.absoluteNonLin(value, 0, 1.0, 4.0)); engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandplay", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); } } else if (control === 0x1C + velSampIdx - 1 && value >= 0x01) { //shifted button deactivates playing sampler or ejects sampler engine.setValue("[Sampler" + samplerOffset + "]", "pregain", 1); if (engine.getValue("[Sampler" + samplerOffset + "]", "play") === 1) { engine.setValue("[Sampler" + samplerOffset + "]", "cue_gotoandstop", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x1C + velSampIdx - 1, MC7000.padColor.velsamploaded); } else { engine.setValue("[Sampler" + samplerOffset + "]", "eject", 1); - // midi.sendShortMsg(0x94 + deckIndex, 0x1C + velSampIdx - 1, MC7000.padColor.velsampoff); engine.setValue("[Sampler" + samplerOffset + "]", "eject", 0); } } @@ -1230,30 +1222,20 @@ MC7000.SamplerLED = function() { if (MC7000.PADModeSampler[deckIdx]) { if (MC7000.SamplerQty === 16) { sampNo = (deckIdx % 2) * 8 + samplerIdx; - var inactiveSamplerDeck = (deckIdx >= 2) ? deckIdx - 2 : deckIdx + 2; } else if (MC7000.SamplerQty === 32) { sampNo = deckIdx * 8 + samplerIdx; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { - if (engine.getValue("[Sampler"+sampNo+"]", "play") === 0) { + var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; + if (samplerIsNotPlaying) { midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); - // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.samplerloaded); //same color when shift is pressed - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); - } + midi.sendShortMsg(0x94 + deckIdx, 0x1C + samplerIdx - 1, MC7000.padColor.samplerloaded); // shift pressed sets the same color } else { midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); - // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.samplerplay); //same color when shift is pressed - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); - } } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); - // midi.sendShortMsg(0x94 + deckIdx, 0x1F + samplerIdx - 1, MC7000.padColor.sampleroff); //same color when shift is pressed - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveSamplerDeck, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); - } + midi.sendShortMsg(0x94 + deckIdx, 0x1C + samplerIdx - 1, MC7000.padColor.sampleroff); // shift pressed sets the same color } } } @@ -1267,8 +1249,7 @@ MC7000.VelSampLED = function() { var sampNo = 0; if (MC7000.PADModeVelSamp[deckIdx]) { if (MC7000.SamplerQty === 16) { - sampNo = (deckIdx % 2) * 8 + velSampIdx; - var inactiveVelSampDeck = (deckIdx >= 2) ? deckIdx - 2 : deckIdx + 2; + sampNo = (deckIdx % 2) * 8 + velSampIdx; // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 } else if (MC7000.SamplerQty === 32) { sampNo = deckIdx * 8 + velSampIdx; // use sampler 1 - sampler 32 for deck 1 - 4 } @@ -1276,21 +1257,14 @@ MC7000.VelSampLED = function() { var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; if (samplerIsNotPlaying) { midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); + midi.sendShortMsg(0x94 + deckIdx, 0x1C + velSampIdx - 1, MC7000.padColor.velsamploaded); // shift pressed sets the same color engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); - } } else { midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); - } } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); - if (MC7000.SamplerQty === 16) { - midi.sendShortMsg(0x94 + inactiveVelSampDeck, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); - } + midi.sendShortMsg(0x94 + deckIdx, 0x1C + velSampIdx - 1, MC7000.padColor.velsampoff); // shift pressed sets the same color } } } From 369062dcf6c64c7a9599eba7f693637e6922b540 Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Feb 2023 18:58:08 +0100 Subject: [PATCH 54/75] changes suggested by JoergAtGithub --- res/controllers/Denon-MC7000-scripts.js | 33 ++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 37d5b780027..5045b813066 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -157,8 +157,8 @@ MC7000.prevPadLED = [0, 0, 0, 0]; MC7000.paramButton = [0, 0, 0, 0]; /* -color codes: -colors are encoded using the following schema: Take the individual components of the color (R, G, B). Then use +Color Codes: +Colors are encoded using the following schema: Take the individual components of the color (R, G, B). Then use the two most significant bits of that color (rr, gg, bb) and pack that into a 7-byte integer using the following schema `0b0rrggbb`. Then add 1 before sending to the controller. */ @@ -1036,14 +1036,11 @@ MC7000.censor = function(channel, control, value, status, group) { } } }; - -// Param Button for Pitch Play to increase or decrease pitch, Star rating otherwise +// Param Button for Pitch Play to decrease pitch, or decrease star rating otherwise MC7000.StarsDown = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; - if (value === 0x00) { - //return; // don't respond to note off messages - } else { + if (value >= 0x00) { if (MC7000.PADModePitch[deckIndex]) { for (var i = 0; i < 8; i++) { MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] - 8; // pitch down @@ -1053,13 +1050,11 @@ MC7000.StarsDown = function(channel, control, value, status, group) { } } }; - +// Param Button for Pitch Play to increase pitch, or increase star rating otherwise MC7000.StarsUp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; - if (value === 0x00) { - //return; // don't respond to note off messages - } else { + if (value >= 0x00) { if (MC7000.PADModePitch[deckIndex]) { for (var i = 0; i < 8; i++) { MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] + 8; // pitch up @@ -1221,20 +1216,22 @@ MC7000.SamplerLED = function() { var sampNo = 0; if (MC7000.PADModeSampler[deckIdx]) { if (MC7000.SamplerQty === 16) { + // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 sampNo = (deckIdx % 2) * 8 + samplerIdx; } else if (MC7000.SamplerQty === 32) { + // use sampler 1 - sampler 32 for deck 1 - 4 sampNo = deckIdx * 8 + samplerIdx; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; if (samplerIsNotPlaying) { - midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerloaded); // set pad color without shift pressed midi.sendShortMsg(0x94 + deckIdx, 0x1C + samplerIdx - 1, MC7000.padColor.samplerloaded); // shift pressed sets the same color } else { midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.samplerplay); } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + samplerIdx - 1, MC7000.padColor.sampleroff); // set pad color without shift pressed midi.sendShortMsg(0x94 + deckIdx, 0x1C + samplerIdx - 1, MC7000.padColor.sampleroff); // shift pressed sets the same color } } @@ -1249,21 +1246,23 @@ MC7000.VelSampLED = function() { var sampNo = 0; if (MC7000.PADModeVelSamp[deckIdx]) { if (MC7000.SamplerQty === 16) { - sampNo = (deckIdx % 2) * 8 + velSampIdx; // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 + // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 + sampNo = (deckIdx % 2) * 8 + velSampIdx; } else if (MC7000.SamplerQty === 32) { - sampNo = deckIdx * 8 + velSampIdx; // use sampler 1 - sampler 32 for deck 1 - 4 + // use sampler 1 - sampler 32 for deck 1 - 4 + sampNo = deckIdx * 8 + velSampIdx; } if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 1) { var samplerIsNotPlaying = engine.getValue("[Sampler"+sampNo+"]", "play") === 0; if (samplerIsNotPlaying) { - midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsamploaded); // set pad color without shift pressed midi.sendShortMsg(0x94 + deckIdx, 0x1C + velSampIdx - 1, MC7000.padColor.velsamploaded); // shift pressed sets the same color engine.setValue("[Sampler"+sampNo+"]", "pregain", 1); } else { midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampplay); } } else if (engine.getValue("[Sampler"+sampNo+"]", "track_loaded") === 0) { - midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); + midi.sendShortMsg(0x94 + deckIdx, 0x14 + velSampIdx - 1, MC7000.padColor.velsampoff); // set pad color without shift pressed midi.sendShortMsg(0x94 + deckIdx, 0x1C + velSampIdx - 1, MC7000.padColor.velsampoff); // shift pressed sets the same color } } From 7b454bf1c8d103de1d349e072fba999c4ef35b79 Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Feb 2023 19:36:11 +0100 Subject: [PATCH 55/75] factor functions renamed, loop variables renamed --- res/controllers/Denon-MC7000-scripts.js | 63 +++++++++++++------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 5045b813066..32bc8fe5c64 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -111,9 +111,9 @@ MC7000.needleSearchTouched = [true, true, true, true]; MC7000.isVinylMode = [MC7000.VinylModeOn, MC7000.VinylModeOn, MC7000.VinylModeOn, MC7000.VinylModeOn]; // initialize the "factor" function for Spinback -MC7000.factor = []; -// initialize the "factor2" function for Brake and Softstart -MC7000.factor2 = []; +MC7000.spinbackFactor = []; +// initialize the "brakeSoftstartFactor" function for Brake and Softstart +MC7000.brakeSoftstartFactor = []; //Set Shift button state to false as default MC7000.shift = [false, false, false, false]; @@ -324,7 +324,7 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckIndex] = false; MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Flip @@ -345,7 +345,7 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckIndex] = false; MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Roll @@ -366,7 +366,7 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckIndex] = false; MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Roll Mode - MC7000.setPadColor(deckIndex, MC7000.padColor.rolloff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.rolloff); }; // PAD Mode Saved Loop @@ -411,7 +411,7 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckIndex] = false; MC7000.PADModePitch[deckIndex] = false; // change PAD color when switching to Slicer Mode - MC7000.setPadColor(deckIndex, MC7000.padColor.sliceron); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.sliceron); }; // PAD Mode Slicer Loop @@ -432,7 +432,7 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { MC7000.PADModeVelSamp[deckIndex] = false; MC7000.PADModePitch[deckIndex] = false; // switch off PAD illumination - MC7000.setPadColor(deckIndex, MC7000.padColor.alloff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; // PAD Mode Sampler @@ -674,14 +674,14 @@ MC7000.PadButtons = function(channel, control, value, status, group) { var hotcueEnabled = engine.getValue(group, "hotcue_" + pitchIdx + "_enabled"), HotcueSelectedOnDeck = MC7000.HotcueSelectedGroup[deckIndex]; if (isButtonPressed && isControlAddress) { if (!HotcueSelectedOnDeck) { - MC7000.setPadColor(deckIndex, MC7000.padColor.pitchoff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.pitchoff); MC7000.HotcueSelectedGroup[deckIndex] = pitchIdx; // store which hotcue should be used for pitch if (!hotcueEnabled) { //hotcue select if none available engine.setValue(group, "hotcue_" + pitchIdx + "_activate", true); // set hotcue if not set before } } else { // hotcue selected and button pressed // TODO: play if play, stop if cue engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckIndex] + "_gotoandstop", true); // stop - MC7000.setPadColor(deckIndex, MC7000.padColor.pitchoff); + MC7000.setAllPadColor(deckIndex, MC7000.padColor.pitchoff); engine.setValue(group, "pitch", MC7000.halftoneToPadMap[deckIndex][pitchIdx - 1]); engine.setValue(group, "hotcue_" + MC7000.HotcueSelectedGroup[deckIndex] + "_gotoandplay", true); midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx - 1, MC7000.padColor.pitchon); // if pitch is pressed switch to pitch on color @@ -711,7 +711,8 @@ MC7000.PadButtons = function(channel, control, value, status, group) { }; -MC7000.setPadColor = function(deckIndex, colorValue) { + +MC7000.setAllPadColor = function(deckIndex, colorValue) { for (var z = 0; z < 8; z++) { // switch 8 buttons to selected color midi.sendShortMsg(0x94 + deckIndex, 0x14 + z, colorValue); @@ -961,8 +962,8 @@ MC7000.stopTime = function(channel, control, value, status, group) { // "factor" for engine.brake() and engine.softStart() // this formula produces factors between 31 (min STOP TIME for ca 7 sec back // in track) and 1 (max STOP TIME for ca 18.0 sec back in track) - MC7000.factor[deckIndex] = (1.1 - (value / 127)) * 30 - 2; - MC7000.factor2[deckIndex] = (127.69 - value); + MC7000.spinbackFactor[deckIndex] = (1.1 - (value / 127)) * 30 - 2; + MC7000.brakeSoftstartFactor[deckIndex] = (127.69 - value); }; MC7000.lastpress = [0, 0, 0, 0]; @@ -974,20 +975,20 @@ MC7000.play = function(channel, control, value, status, group) { var deckIndex = deckNumber - 1; // set a variable to toggle between play and pause, based on current play status var playToggle = engine.getValue(group, "play"); - if (MC7000.factor[deckIndex] === 31) { // factor 31 means stop time knob is at zero position + if (MC7000.spinbackFactor[deckIndex] === 31) { // factor 31 means stop time knob is at zero position engine.setValue(group, "play", !playToggle); MC7000.lastpress[deckIndex] = 0; } else { if (playToggle) { if (!MC7000.lastpress[deckIndex]) { - engine.brake(deckNumber, true, MC7000.factor2[deckIndex]); + engine.brake(deckNumber, true, MC7000.brakeSoftstartFactor[deckIndex]); MC7000.lastpress[deckIndex] = 1; } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckIndex]); + engine.softStart(deckNumber, true, MC7000.brakeSoftstartFactor[deckIndex]); MC7000.lastpress[deckIndex] = 0; } } else { - engine.softStart(deckNumber, true, MC7000.factor2[deckIndex]); + engine.softStart(deckNumber, true, MC7000.brakeSoftstartFactor[deckIndex]); MC7000.lastpress[deckIndex] = 0; } } @@ -999,8 +1000,8 @@ MC7000.reverse = function(channel, control, value, status, group) { var deckIndex = deckNumber - 1; if (value > 0) { // while the button is pressed spin back - // start at a rate of -10 and decrease by "MC7000.factor" - engine.brake(deckNumber, true, MC7000.factor[deckIndex], -10); + // start at a rate of -10 and decrease by "MC7000.spinbackFactor" + engine.brake(deckNumber, true, MC7000.spinbackFactor[deckIndex], -10); } else { if (engine.getValue(group, "slip_enabled")) { engine.brake(deckNumber, false); // disable brake effect @@ -1010,7 +1011,7 @@ MC7000.reverse = function(channel, control, value, status, group) { engine.setValue(group, "slip_enabled", true); }, true); } else { - engine.softStart(deckNumber, true, MC7000.factor[deckIndex]); + engine.softStart(deckNumber, true, MC7000.spinbackFactor[deckIndex]); } } }; @@ -1042,8 +1043,8 @@ MC7000.StarsDown = function(channel, control, value, status, group) { var deckIndex = deckNumber - 1; if (value >= 0x00) { if (MC7000.PADModePitch[deckIndex]) { - for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] - 8; // pitch down + for (var padIdx = 0; padIdx < 8; padIdx++) { + MC7000.halftoneToPadMap[deckIndex][padIdx] = MC7000.halftoneToPadMap[deckIndex][padIdx] - 8; // pitch down } } else { engine.setValue(group, "stars_down", true); // stars down @@ -1056,8 +1057,8 @@ MC7000.StarsUp = function(channel, control, value, status, group) { var deckIndex = deckNumber - 1; if (value >= 0x00) { if (MC7000.PADModePitch[deckIndex]) { - for (var i = 0; i < 8; i++) { - MC7000.halftoneToPadMap[deckIndex][i] = MC7000.halftoneToPadMap[deckIndex][i] + 8; // pitch up + for (var padIdx = 0; padIdx < 8; padIdx++) { + MC7000.halftoneToPadMap[deckIndex][padIdx] = MC7000.halftoneToPadMap[deckIndex][padIdx] + 8; // pitch up } } else { engine.setValue(group, "stars_up", true); // stars up @@ -1193,16 +1194,16 @@ MC7000.HotCueLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; if (MC7000.PADModeCue[deckIndex]) { - for (var i = 1; i <= 8; i++) { + for (var padIdx = 1; padIdx <= 8; padIdx++) { if (value === 1) { - if (engine.getValue(group, "hotcue_"+i+"_enabled") === 1) { - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.hotcueon); - midi.sendShortMsg(0x94 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueon); + if (engine.getValue(group, "hotcue_"+padIdx+"_enabled") === 1) { + midi.sendShortMsg(0x94 + deckIndex, 0x14 + padIdx - 1, MC7000.padColor.hotcueon); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + padIdx - 1, MC7000.padColor.hotcueon); } } else { - if (engine.getValue(group, "hotcue_"+i+"_enabled") === 0) { - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.hotcueoff); - midi.sendShortMsg(0x94 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueoff); + if (engine.getValue(group, "hotcue_"+padIdx+"_enabled") === 0) { + midi.sendShortMsg(0x94 + deckIndex, 0x14 + padIdx - 1, MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + padIdx - 1, MC7000.padColor.hotcueoff); } } } From 1889340cb816ade7ce4f9def7096c3cf4f0f4d99 Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Feb 2023 19:49:22 +0100 Subject: [PATCH 56/75] factor in comment changed to spinbackFactor --- res/controllers/Denon-MC7000-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 32bc8fe5c64..507d1cdc5e9 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -110,7 +110,7 @@ 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]; -// initialize the "factor" function for Spinback +// initialize the "spinnbackFactor" function for Spinback MC7000.spinbackFactor = []; // initialize the "brakeSoftstartFactor" function for Brake and Softstart MC7000.brakeSoftstartFactor = []; From 8b9647f95e5590aeb7088281e4cf6fb785758616 Mon Sep 17 00:00:00 2001 From: holopansel Date: Sun, 12 Feb 2023 21:46:46 +0100 Subject: [PATCH 57/75] PADMode variables updated, init function grouping of loops --- res/controllers/Denon-MC7000-scripts.js | 267 ++++++++---------------- 1 file changed, 82 insertions(+), 185 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 507d1cdc5e9..753db225bab 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -121,17 +121,8 @@ MC7000.shift = [false, false, false, false]; // For each side whether the top or bottom deck is active. MC7000.topDeckActive = [true, true]; -// initialize the PAD Mode to Hot Cue and all others off when starting -MC7000.PADModeCue = [true, true, true, true]; -MC7000.PADModeCueLoop = [false, false, false, false]; -MC7000.PADModeFlip = [false, false, false, false]; -MC7000.PADModeRoll = [false, false, false, false]; -MC7000.PADModeSavedLoop = [false, false, false, false]; -MC7000.PADModeSlicer = [false, false, false, false]; -MC7000.PADModeSlicerLoop = [false, false, false, false]; -MC7000.PADModeSampler = [false, false, false, false]; -MC7000.PADModeVelSamp = [false, false, false, false]; -MC7000.PADModePitch = [false, false, false, false]; +// initialize the PAD Mode to Hot Cue when starting +MC7000.PADMode = ["Cue", "Cue", "Cue", "Cue"]; // PAD Mode 'Beatloop Roll' sizes MC7000.beatLoopRoll = [1 / 16, 1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8]; @@ -235,29 +226,22 @@ MC7000.init = function() { midi.sendShortMsg(0x92, 0x07, MC7000.isVinylMode ? 0x7F: 0x01); midi.sendShortMsg(0x93, 0x07, MC7000.isVinylMode ? 0x7F: 0x01); - // HotCue Mode LEDs - for (var cueIdx = 1; cueIdx <= 8; cueIdx++) { - engine.makeConnection("[Channel1]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel2]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel3]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); - engine.makeConnection("[Channel4]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); + for (var chanIdx = 1; chanIdx <= 4; chanIdx++) { + // HotCue Mode LEDs + for (var cueIdx = 1; cueIdx <= 8; cueIdx++) { + engine.makeConnection("[Channel"+chanIdx+"]", "hotcue_"+cueIdx+"_enabled", MC7000.HotCueLED); + } + // Pitch LEDs + for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { + engine.makeConnection("[Channel"+chanIdx+"]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); + } } - // Sampler Mode LEDs + // Sampler Mode LEDs and Velocity Sampler Mode LEDs for (var samplerIdx = 1; samplerIdx <= MC7000.SamplerQty; samplerIdx++) { engine.makeConnection("[Sampler"+samplerIdx+"]", "track_loaded", MC7000.SamplerLED); engine.makeConnection("[Sampler"+samplerIdx+"]", "play", MC7000.SamplerLED); - } - // Velocity Sampler Mode LEDs - for (var velSampIdx = 1; velSampIdx <= MC7000.SamplerQty; velSampIdx++) { - engine.makeConnection("[Sampler"+velSampIdx+"]", "track_loaded", MC7000.VelSampLED); - engine.makeConnection("[Sampler"+velSampIdx+"]", "play", MC7000.VelSampLED); - } - //Pitch LEDs - for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { - engine.makeConnection("[Channel1]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel2]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel3]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); - engine.makeConnection("[Channel4]", "hotcue_"+pitchIdx+"_enabled", MC7000.PitchLED); + engine.makeConnection("[Sampler"+samplerIdx+"]", "track_loaded", MC7000.VelSampLED); + engine.makeConnection("[Sampler"+samplerIdx+"]", "play", MC7000.VelSampLED); } // send Softtakeover delayed to avoid conflicts with ControllerStatusSysex engine.beginTimer(2000, function() { @@ -289,20 +273,11 @@ MC7000.padModeCue = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = true; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "Cue"; // change PAD color when switching to Hot Cue Mode - for (var i = 1; i <= 8; i++) { - var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + for (var cueIdx = 1; cueIdx <= 8; cueIdx++) { + var hotcueEnabled = engine.getValue(group, "hotcue_" + cueIdx + "_enabled", true); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + cueIdx - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } }; @@ -313,16 +288,7 @@ MC7000.padModeCueLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = true; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "CueLoop"; // switch off PAD illumination MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; @@ -334,16 +300,7 @@ MC7000.padModeFlip = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = true; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "Flip"; // switch off PAD illumination MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; @@ -355,16 +312,7 @@ MC7000.padModeRoll = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = true; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "Roll"; // change PAD color when switching to Roll Mode MC7000.setAllPadColor(deckIndex, MC7000.padColor.rolloff); }; @@ -376,20 +324,11 @@ MC7000.padModeSavedLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = true; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "SavedLoop"; // change PAD color when switching to Saved Loop Mode - for (var i = 0; i < 8; i++) { - var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, activeLED); + for (var savedLoopIdx = 0; savedLoopIdx < 8; savedLoopIdx++) { + var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[savedLoopIdx] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; + midi.sendShortMsg(0x94 + deckIndex, 0x14 + savedLoopIdx, activeLED); } }; @@ -400,16 +339,7 @@ MC7000.padModeSlicer = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = true; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "Slicer"; // change PAD color when switching to Slicer Mode MC7000.setAllPadColor(deckIndex, MC7000.padColor.sliceron); }; @@ -421,16 +351,7 @@ MC7000.padModeSlicerLoop = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = true; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "SlicerLoop"; // switch off PAD illumination MC7000.setAllPadColor(deckIndex, MC7000.padColor.alloff); }; @@ -442,16 +363,7 @@ MC7000.padModeSampler = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = true; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "Sampler"; // change PAD color when switching to Sampler Mode MC7000.SamplerLED(); }; @@ -463,16 +375,7 @@ MC7000.padModeVelSamp = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = true; - MC7000.PADModePitch[deckIndex] = false; + MC7000.PADMode[deckIndex] = "VelSamp"; // change PAD color when switching to Velocity Sampler Mode MC7000.VelSampLED(); }; @@ -485,27 +388,16 @@ MC7000.padModePitch = function(channel, control, value, status, group) { if (value === 0x00) { return; // don't respond to note off messages } + MC7000.PADMode[deckIndex] = "Pitch"; MC7000.halftoneToPadMap[deckIndex] = [4, 5, 6, 7, 0, 1, 2, 3]; - - MC7000.PADModeCue[deckIndex] = false; - MC7000.PADModeCueLoop[deckIndex] = false; - MC7000.PADModeFlip[deckIndex] = false; - MC7000.PADModeRoll[deckIndex] = false; - MC7000.PADModeSavedLoop[deckIndex] = false; - MC7000.PADModeSlicer[deckIndex] = false; - MC7000.PADModeSlicerLoop[deckIndex] = false; - MC7000.PADModeSampler[deckIndex] = false; - MC7000.PADModeVelSamp[deckIndex] = false; - MC7000.PADModePitch[deckIndex] = true; - // switch on initial PAD illumination = hotcue for pitch or if // MC7000.HotcueSelectedGroup selected = pad mode pitchoff color - for (var i = 1; i <= 8; i++) { + for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { if (MC7000.HotcueSelectedGroup[deckIndex] !== 0) { - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, MC7000.padColor.pitchoff); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx - 1, MC7000.padColor.pitchoff); } else { - var hotcueEnabled = engine.getValue(group, "hotcue_" + i + "_enabled", true); - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + var hotcueEnabled = engine.getValue(group, "hotcue_" + pitchIdx + "_enabled", true); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + pitchIdx - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); } } }; @@ -515,7 +407,7 @@ MC7000.padModePitch = function(channel, control, value, status, group) { MC7000.PadButtons = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; - var i, j, z; + var i, j; // The following modes are currently unhandled and could be // added as if-branches in the future: @@ -525,24 +417,24 @@ MC7000.PadButtons = function(channel, control, value, status, group) { // - MC7000.PADModeSlicerLoop // activate and clear Hot Cues - if (MC7000.PADModeCue[deckIndex] && engine.getValue(group, "track_loaded") === 1) { - for (i = 1; i <= 8; i++) { - if (control === 0x14 + i - 1 && value === 0x7F) { - engine.setValue(group, "hotcue_" + i + "_activate", true); - } else if (control === 0x14 + i - 1 && value === 0x00) { - engine.setValue(group, "hotcue_" + i + "_activate", false); + if (MC7000.PADMode[deckIndex] === "Cue" && engine.getValue(group, "track_loaded") === 1) { + for (var cueIdx = 1; cueIdx <= 8; cueIdx++) { + if (control === 0x14 + cueIdx - 1 && value === 0x7F) { + engine.setValue(group, "hotcue_" + cueIdx + "_activate", true); + } else if (control === 0x14 + cueIdx - 1 && value === 0x00) { + engine.setValue(group, "hotcue_" + cueIdx + "_activate", false); 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 + deckIndex, 0x1C + i - 1, MC7000.padColor.hotcueoff); + } else if (control === 0x1C + cueIdx - 1 && value === 0x7F) { + engine.setValue(group, "hotcue_" + cueIdx + "_clear", true); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + cueIdx - 1, MC7000.padColor.hotcueoff); } } - } else if (MC7000.PADModeRoll[deckIndex]) { + } else if (MC7000.PADMode[deckIndex] === "Roll") { // TODO(all): check for actual beatloop_size and apply back after a PAD Roll i = control - 0x14; if (control === 0x14 + i && value > 0x00) { @@ -552,17 +444,17 @@ MC7000.PadButtons = function(channel, control, value, status, group) { engine.setValue(group, "beatlooproll_activate", false); midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, MC7000.padColor.rolloff); } - } else if (MC7000.PADModeSavedLoop[deckIndex]) { + } else if (MC7000.PADMode[deckIndex] === "SavedLoop") { if (value === 0x00) { return; // don't respond to note off messages } i = control - 0x14; engine.setValue(group, "beatloop_" + MC7000.fixedLoop[i] + "_toggle", true); - for (j = 0; j < 8; j++) { - var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[j] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; - midi.sendShortMsg(0x94 + deckIndex, 0x14 + j, activeLED); + for (var loopIdx = 0; loopIdx < 8; loopIdx++) { + var activeLED = engine.getValue(group, "beatloop_" + MC7000.fixedLoop[loopIdx] + "_enabled") ? MC7000.padColor.fixedloopon : MC7000.padColor.fixedloopoff; + midi.sendShortMsg(0x94 + deckIndex, 0x14 + loopIdx, activeLED); } - } else if (MC7000.PADModeSlicer[deckIndex]) { + } else if (MC7000.PADMode[deckIndex] === "Slicer") { if (value > 0) { i = control - 0x14; // unshifted button j = control - 0x1C; // shifted button @@ -586,9 +478,9 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else { midi.sendShortMsg(0x94 + deckIndex, control, MC7000.padColor.sliceron); } - } else if (MC7000.PADModeSampler[deckIndex]) { + } else if (MC7000.PADMode[deckIndex] === "Sampler") { var samplerOffset = 0; - var samplerOffsetJ = 0; + var samplerOffsetStop = 0; var deckOffset = 0; for (var samplerIdx = 1; samplerIdx <= 8; samplerIdx++) { if (MC7000.SamplerQty === 16) { @@ -603,10 +495,10 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck - for (j = 1; j <= 8; j++) { - samplerOffsetJ = deckOffset + j; - if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it - engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + for (var samplerStopIdx = 1; samplerStopIdx <= 8; samplerStopIdx++) { + samplerOffsetStop = deckOffset + samplerStopIdx; + if (engine.getValue("[Sampler" + samplerOffsetStop + "]", "play") === 1) { // if sampler is playing then stop it + engine.setValue("[Sampler" + samplerOffsetStop + "]", "cue_gotoandstop", 1); } } } @@ -624,9 +516,9 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } MC7000.SamplerLED(); } - } else if (MC7000.PADModeVelSamp[deckIndex]) { + } else if (MC7000.PADMode[deckIndex] === "VelSamp") { samplerOffset = 0; - samplerOffsetJ = 0; + samplerOffsetStop = 0; deckOffset = 0; for (var velSampIdx = 1; velSampIdx <= 8; velSampIdx++) { if (MC7000.SamplerQty === 16) { @@ -641,10 +533,10 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else if (engine.getValue("[Sampler" + samplerOffset + "]", "track_loaded") === 1) { if (MC7000.prevSamplerStop) { // stop playing all other samplers on this deck - for (j = 1; j <= 8; j++) { - samplerOffsetJ = deckOffset + j; - if (engine.getValue("[Sampler" + samplerOffsetJ + "]", "play") === 1) { // if sampler is playing then stop it - engine.setValue("[Sampler" + samplerOffsetJ + "]", "cue_gotoandstop", 1); + for (samplerStopIdx = 1; samplerStopIdx <= 8; samplerStopIdx++) { + samplerOffsetStop = deckOffset + samplerStopIdx; + if (engine.getValue("[Sampler" + samplerOffsetStop + "]", "play") === 1) { // if sampler is playing then stop it + engine.setValue("[Sampler" + samplerOffsetStop + "]", "cue_gotoandstop", 1); } } } @@ -663,7 +555,7 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } MC7000.VelSampLED(); } - } else if (MC7000.PADModePitch[deckIndex]) { // TODO play and cue dependency to play and cue button + } else if (MC7000.PADMode[deckIndex] === "Pitch") { // TODO play and cue dependency to play and cue button if (engine.getValue(group, "track_loaded") === 1) { for (var pitchIdx = 1; pitchIdx <= 8; pitchIdx++) { // intermediate variables @@ -699,10 +591,10 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } else if (isButtonPressed && isControlAddressShift) { //shifted buttons deselect hotcue for pitch engine.setValue(group, "pitch", 0); MC7000.HotcueSelectedGroup[deckIndex] = 0; - for (z = 1; z <= 8; z++) { - hotcueEnabled = engine.getValue(group, "hotcue_" + z + "_enabled", true); - midi.sendShortMsg(0x94 + deckIndex, 0x14 + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); - midi.sendShortMsg(0x94 + deckIndex, 0x1C + z - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed + for (var padIdx = 1; padIdx <= 8; padIdx++) { + hotcueEnabled = engine.getValue(group, "hotcue_" + padIdx + "_enabled", true); + midi.sendShortMsg(0x94 + deckIndex, 0x14 + padIdx - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + padIdx - 1, hotcueEnabled ? MC7000.padColor.hotcueon : MC7000.padColor.hotcueoff); // keep color when shift is pressed } } } @@ -710,13 +602,18 @@ MC7000.PadButtons = function(channel, control, value, status, group) { } }; - +// Set single LED color for future implementation +//MC7000.setSinglePadColor = function(deckIdx, padIdx, colorValue) { +// switch 1 buttons to selected color, also when shift is pressed +// midi.sendShortMsg(0x94 + deckIdx, 0x14 + padIdx, colorValue); +// midi.sendShortMsg(0x94 + deckIdx, 0x1C + padIdx, colorValue); // keep color when shift is pressed +//}; MC7000.setAllPadColor = function(deckIndex, colorValue) { - for (var z = 0; z < 8; z++) { + for (var padIdx = 0; padIdx < 8; padIdx++) { // switch 8 buttons to selected color - midi.sendShortMsg(0x94 + deckIndex, 0x14 + z, colorValue); - midi.sendShortMsg(0x94 + deckIndex, 0x1C + z, colorValue); // keep color when shift is pressed + midi.sendShortMsg(0x94 + deckIndex, 0x14 + padIdx, colorValue); + midi.sendShortMsg(0x94 + deckIndex, 0x1C + padIdx, colorValue); // keep color when shift is pressed } }; @@ -1170,8 +1067,8 @@ MC7000.TrackPositionLEDs = function(value, group) { // only send new LED status when beatCountLED really changes if (MC7000.prevPadLED[deckIndex] !== beatCountLED) { // first set all LEDs to default color incl shifted - for (var i = 0; i < 16; i++) { - midi.sendShortMsg(0x94 + deckIndex, 0x14 + i, MC7000.padColor.sliceron); + for (var slicerIdx = 0; slicerIdx < 16; slicerIdx++) { + midi.sendShortMsg(0x94 + deckIndex, 0x14 + slicerIdx, MC7000.padColor.sliceron); } // now chose which PAD LED to turn on (+8 means shifted PAD LEDs) if (beatCountLED === 0) { @@ -1193,7 +1090,7 @@ MC7000.TrackPositionLEDs = function(value, group) { MC7000.HotCueLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; - if (MC7000.PADModeCue[deckIndex]) { + if (MC7000.PADMode[deckIndex] === "Cue") { for (var padIdx = 1; padIdx <= 8; padIdx++) { if (value === 1) { if (engine.getValue(group, "hotcue_"+padIdx+"_enabled") === 1) { @@ -1215,7 +1112,7 @@ MC7000.SamplerLED = function() { for (var deckIdx = 0; deckIdx < 4; deckIdx++) { for (var samplerIdx = 1; samplerIdx <= 8; samplerIdx++) { var sampNo = 0; - if (MC7000.PADModeSampler[deckIdx]) { + if (MC7000.PADMode[deckIdx] === "Sampler") { if (MC7000.SamplerQty === 16) { // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 sampNo = (deckIdx % 2) * 8 + samplerIdx; @@ -1245,7 +1142,7 @@ MC7000.VelSampLED = function() { for (var deckIdx = 0; deckIdx < 4; deckIdx++) { for (var velSampIdx = 1; velSampIdx <= 8; velSampIdx++) { var sampNo = 0; - if (MC7000.PADModeVelSamp[deckIdx]) { + if (MC7000.PADMode[deckIdx] === "VelSamp") { if (MC7000.SamplerQty === 16) { // use sampler 1-16 for deck 1 and deck 2 and sampler 1-16 for deck 3 and 4 sampNo = (deckIdx % 2) * 8 + velSampIdx; @@ -1275,7 +1172,7 @@ MC7000.VelSampLED = function() { MC7000.PitchLED = function(value, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; - if (MC7000.PADModePitch[deckIndex]) { + if (MC7000.PADMode[deckIndex] === "Pitch") { for (var pitchIdx = 0; pitchIdx < 8; pitchIdx++) { if (engine.getValue("[Channel"+deckNumber+"]", "play") === 0) { // stopped if (MC7000.HotcueSelectedGroup[deckIndex] !== 0) { // hotcue selected From a2d862a149c92a45977adb93c4ce167581a73c63 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Sun, 12 Feb 2023 22:23:54 +0100 Subject: [PATCH 58/75] fix: build after untested merge --- src/test/searchqueryparsertest.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index 6a0335d54b8..5ac26f9b8c1 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -338,11 +338,10 @@ TEST_F(SearchQueryParserTest, NumericFilter) { } TEST_F(SearchQueryParserTest, NumericFilterYear) { - QStringList searchColumns; - searchColumns << "year"; + m_parser.setSearchColumns({"year"}); auto pQuery( - m_parser.parseQuery("year:1969", searchColumns, "")); + m_parser.parseQuery("year:1969", QString())); TrackPointer pTrack = newTestTrack(44100); EXPECT_FALSE(pQuery->match(pTrack)); From d54bc1b30686a1891644b74fe3f6bf39e031cbe3 Mon Sep 17 00:00:00 2001 From: holopansel Date: Mon, 13 Feb 2023 16:01:07 +0100 Subject: [PATCH 59/75] error correction in param buttons --- res/controllers/Denon-MC7000-scripts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js index 753db225bab..82d057d26a8 100755 --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -939,7 +939,7 @@ MC7000.StarsDown = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; if (value >= 0x00) { - if (MC7000.PADModePitch[deckIndex]) { + if (MC7000.PADMode[deckIndex] === "Pitch") { for (var padIdx = 0; padIdx < 8; padIdx++) { MC7000.halftoneToPadMap[deckIndex][padIdx] = MC7000.halftoneToPadMap[deckIndex][padIdx] - 8; // pitch down } @@ -953,7 +953,7 @@ MC7000.StarsUp = function(channel, control, value, status, group) { var deckNumber = script.deckFromGroup(group); var deckIndex = deckNumber - 1; if (value >= 0x00) { - if (MC7000.PADModePitch[deckIndex]) { + if (MC7000.PADMode[deckIndex] === "Pitch") { for (var padIdx = 0; padIdx < 8; padIdx++) { MC7000.halftoneToPadMap[deckIndex][padIdx] = MC7000.halftoneToPadMap[deckIndex][padIdx] + 8; // pitch up } From 97fe176928c1e0782d7d13486a494ca55016806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 14 Feb 2023 20:59:13 +0100 Subject: [PATCH 60/75] Added Bilal Ahmed Karbelkar to the contributor list in the about box. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 48c1947f6d5..dc10fd85a49 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -120,7 +120,8 @@ DlgAbout::DlgAbout() << "Somesh Metri" << "Maarten de Boer" << "Doteya" - << "olafklingt"; + << "olafklingt" + << "Bilal Ahmed Karbelkar"; QStringList specialThanks; specialThanks From dc33287a42d14bfa7134bf21b50de4d7ff9d8a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 14 Feb 2023 21:15:22 +0100 Subject: [PATCH 61/75] Added Alice Psykose to the contributor list in the about box. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index dc10fd85a49..2c3782ad48a 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -121,7 +121,8 @@ DlgAbout::DlgAbout() << "Maarten de Boer" << "Doteya" << "olafklingt" - << "Bilal Ahmed Karbelkar"; + << "Bilal Ahmed Karbelkar" + << "Alice Psykose"; QStringList specialThanks; specialThanks From d77130322021ca1ec0860cea4d0690cd86a9ee84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 14 Feb 2023 21:21:38 +0100 Subject: [PATCH 62/75] Added Jakob Leifhelm to the contributor list in the about box. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 2c3782ad48a..5f407fd1adb 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -122,7 +122,8 @@ DlgAbout::DlgAbout() << "Doteya" << "olafklingt" << "Bilal Ahmed Karbelkar" - << "Alice Psykose"; + << "Alice Psykose" + << "Jakob Leifhelm"; QStringList specialThanks; specialThanks From bea20edd9dc14c1bfeb15960715133fe702e8b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 14 Feb 2023 21:26:42 +0100 Subject: [PATCH 63/75] Added Florian Goth to the contributor list in the about box. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 5f407fd1adb..89204f45dcb 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -123,7 +123,8 @@ DlgAbout::DlgAbout() << "olafklingt" << "Bilal Ahmed Karbelkar" << "Alice Psykose" - << "Jakob Leifhelm"; + << "Jakob Leifhelm" + << "Florian Goth"; QStringList specialThanks; specialThanks From 902476bcf70f4d583fb573bd8e7508d88595eb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 14 Feb 2023 21:30:17 +0100 Subject: [PATCH 64/75] Added Chase Durand to the contributor list in the about box. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 89204f45dcb..ce60da9df7b 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -124,7 +124,8 @@ DlgAbout::DlgAbout() << "Bilal Ahmed Karbelkar" << "Alice Psykose" << "Jakob Leifhelm" - << "Florian Goth"; + << "Florian Goth" + << "Chase Durand"; QStringList specialThanks; specialThanks From ed883451980a2696a63bb6324405ac3909509021 Mon Sep 17 00:00:00 2001 From: holopansel Date: Wed, 15 Feb 2023 07:06:10 +0100 Subject: [PATCH 65/75] user rights changed, comment for samplers added according to request from manual section --- res/controllers/Denon-MC7000-scripts.js | 5 +++++ 1 file changed, 5 insertions(+) mode change 100755 => 100644 res/controllers/Denon-MC7000-scripts.js diff --git a/res/controllers/Denon-MC7000-scripts.js b/res/controllers/Denon-MC7000-scripts.js old mode 100755 new mode 100644 index 82d057d26a8..5bdb46ff79f --- a/res/controllers/Denon-MC7000-scripts.js +++ b/res/controllers/Denon-MC7000-scripts.js @@ -50,6 +50,11 @@ MC7000.needleSearchPlay = false; MC7000.prevSamplerStop = true; // Quantity of Samplers used in mixxx possible values 16 and 32 +// To use 32 samplers instead of 16 you can set the user variable +// MC7000.SamplerQty to 32. Deck 1 will trigger sampler 1 to 8, +// Deck 2 will trigger sampler 9 to 16, Deck 3 will trigger +// sampler 17 to 24 and Deck 4 will trigger sampler 25 to 32. +// Please note that your Mixxx skin needs to support more than 16 samplers. MC7000.SamplerQty = 16; // Set Vinyl Mode on ("true") or off ("false") when MIXXX starts. From 67159f279d272697ab7fd12521c201a2c23e9829 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Wed, 3 Aug 2022 01:36:23 +0200 Subject: [PATCH 66/75] feat(tools): add python script used for migrating to github issues --- .codespellignore | 1 + tools/json2github.py | 666 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 667 insertions(+) create mode 100644 tools/json2github.py diff --git a/.codespellignore b/.codespellignore index c5c9c8e31b5..89eae26d2f6 100644 --- a/.codespellignore +++ b/.codespellignore @@ -2,3 +2,4 @@ crate copyable doubleclick technics +jus diff --git a/tools/json2github.py b/tools/json2github.py new file mode 100644 index 00000000000..7dc8c9083da --- /dev/null +++ b/tools/json2github.py @@ -0,0 +1,666 @@ +#!/usr/bin/env python3 +""" +Alternative lp2gh JSON Importer for Mixxx issue migration + +You can install this like this: + + $ python3 -m venv venv + $ source venv/bin/activate + $ pip install PyGithub + +To use it, you first need to obtain a bugs and milestone json file from lp2gh: + + https://github.com/Swiftb0y/lp2gh/blob/mixxx-import-fork/docs/moving_issues.rst#exporting-your-bugs + https://github.com/Swiftb0y/lp2gh/blob/mixxx-import-fork/docs/moving_issues.rst#exporting-your-milestones + +Its important you are using my Fork with the `mixxx-import-fork` branch as I +made some slight modifications to add features. + +You can use it like this: + + $ python json2github.py --repo Holzhaus/mixxx-gh-issue-migration \ + --token mytoken --output-file=mixxx_bugs.json \ + mixxx_bugs.json mixxx_milestones.json + +""" +import argparse +import binascii +import datetime +import json +import logging +import random +import re +import textwrap +import time +import github + +LAUNCHPAD_STATUS_MAP = { + "Confirmed": ["confirmed"], + "Fix Committed": [], + "Fix Released": [], + "Incomplete": ["incomplete"], + "In Progress": [], + "Invalid": ["invalid"], + "New": [], + "Triaged": ["confirmed"], + "Won't Fix": ["wontfix"], + "Opinion": ["opinion"], + "Expired": ["expired"], +} + +LAUNCHPAD_IMPORTANCE_MAP = { + "Critical": ["party stopper", "bug"], + "High": ["bug"], + "Low": ["bug"], + "Medium": ["bug"], + "Undecided": [], + "Wishlist": ["feature"], +} + +LAUNCHPAD_USER_MAP = { + "aart": "amvanbaren", + "alex-jercaianu": "jercaianu", + "alex.barker": "kwhat", + # (not sure, email on launchpad matches + # with domain linked on github profile) + "another-rob": "borfo", + "arbeit-u": "dg3nec", + "arli0715": "dodler", + "badescunicu": "badescunicu", + "be.ing": "Be-ing", + "bencoder": "bencoder", + "bkgood": "bkgood", + "bruno-buccolo": "buccolo", + "buzz-dee": "BuZZ-dEE", + "cardinot": "cardinot", + "chloe-avrillon": "DJChloe", + "crislacerda": "crislacerda", + "daniel-64studio": "danielhjames", + "daschuer": "daschuer", + "default-kramer": "default-kramer", + "dj-kaza": "kazakore", + "eradkoff12": "radkoff", + "ewanuno": "ewanuno", # (not sure) + "federicobriata": "federicobriata", + "ferranpujol": "ferranpujolcamins", + "foss4": "foss-", + "frank-breitling": "fkbreitl", + "gamegod": "asantoni", + "gmsoft": "gmsoft-tuxicoman", + "goddisignz": "goddisignz", + "hacksdump": "hacksdump", + "hile": "hile", + "holthuis-jan": "Holzhaus", + "htown202": "htown101", + "iamcodemaker": "iamcodemaker", + "ironstorm-gmail": "deftdawg", + "jatwill": "idcmp", + "jean-claveau-g": "jclaveau", + "jessboerner": "doodlebro", + "jmigual": "jmigual", + "joerg-ubuntu": "JoergAtGithub", + "johan-lasperas": "johanLsp", + "josepma": "JosepMaJAZ", + "juha-pitkanen": "JuhaPit", + "jus": "esbrandt", + "kabelfrickler": "snue", + "kek001": "kek001", + "ketanlambat": "ketan-lambat", + "kevin-m-wern": "kevinwern", + "khyew": "khyew", + "kousu": "kousu", # not sure, but first name seems to match + "kshitij98": "kshitij98", + "launchpad-net-poelzi": "poelzi", + "lbot": "leematos", + "leigh123linux-j": "leigh123linux", + "lindybalboa": "LindyBalboa", + "marczis": "marczis", + "markusb": "markusb", + "max-linke": "kain88-de", + "mdizer": "mdizer", + "melgrubb": "MelGrubb", + "metastableb": "metastableB", + "mevsme": "mevsme", + "mhaulo": "mhaulo", + "michael-z-freeman": "Michael-Z-Freeman", + "mxmilkiib": "mxmilkiib", + "nachtigall": "jenszo", + "naught101": "naught101", + "nik-martin": "nikmartin", + "nimitbhardwaj": "nimitbhardwaj", + "ninomp": "ninomp", + "nm2107": "nm2107", + "nopeppermint": "nopeppermint", + "nschloe": "nschloe", + "pasanen-tuukka": "illuusio", + "pegasus-renegadetech": "Pegasus-RPG", + "pestrela": "pestrela", + "poelzi": "poelzi", + "pwhelan": "pwhelan", + "quentinfaidide": "QuentinFAIDIDE", + "raulbehl": "raulbehl", + "rawrr": "rawrr", + "ronso0": "ronso0", + "rryan": "rryan", + "sblaisot": "sblaisot", + "smashuu": "smashuu", + "stephane-guillou": "stragu", + "swiftb0y": "Swiftb0y", + "toszlanyi": "toszlanyi", + "troyane3": "troyane", + "uklotzde": "uklotzde", + "ulatekh": "ulatekh", + "vlada-dudr": "vlada-dudr", + "vrince": "vrince", + "wzssyqa": "wzssyqa", + "xerus2000": "xeruf", + "xor29a": "xorik", + "ywwg": "ywwg", + "zezic": "zezic", +} + +# Github has restrictions on assignees +# Since this script was made to import to a private repo and transfer over +# afterwards, most assignees would be invalid and so we won't use them. +GITHUB_ALLOWED_ASSIGNEES = { + # "Holzhaus", + # "asantoni", + # "Be-ing", + # "daschuer", + # "esbrandt", + # "Pegasus-RPG", + # "ronso0", + # "rryan", + # "sblaisot", + # "Swiftb0y", + # "uklotzde", + # "ywwg", +} + +LABELS = { + "aac": None, + "accessibility": None, + "analyzer": None, + "autodj": None, + "auxiliary": None, + "beatgrid": None, + "bpm": None, + "broadcast": None, + "browse": None, + "build": None, + "cloud": None, + "cmake": None, + "controllers": None, + "coverart": None, + "crash": None, + "cue": None, + "effects": None, + "engine": None, + "eq": None, + "follower": None, + "gui": None, + "hid": None, + "i18n": None, + "installer": None, + "itunes": None, + "jack": None, + "key": None, + "keyboard": None, + "library": None, + "looping": None, + "lyrics": None, + "m4a": None, + "manual": None, + "metadata": None, + "microphone": None, + "midi": None, + "mp3": None, + "overview": None, + "packaging": None, + "passthrough": None, + "performance": None, + "playlist": None, + "polish": None, + "portaudio": None, + "preferences": None, + "qt5": None, + "quantize": None, + "recording": None, + "rekordbox": None, + "sampler": None, + "scanner": None, + "serato": None, + "skin": None, + "slip": None, + "soundio": None, + "soundsource": None, + "standards": None, + "sync": None, + "tooltip": None, + "touchscreen": None, + "transport": None, + "usability": None, + "vinylcontrol": None, + "waveform": None, + # Importance (red) + "bug": "ff0000", + "security": "ff4400", + "regression": "ef233c", + "party stopper": "7b0d1e", + "feature": "bd2d87", + # status (yellow-ish) + "incomplete": "fff45c", + "invalid": "f9e900", + "confirmed": "faa916", + "wontfix": "ccbe00", + "duplicate": "8f8500", + "opinion": "9e9517", + "expired": "b5bf00", + # target system (blue-ish) + "windows": "1929b3", + "linux": "3b4be3", + "macos": "121d7d", + "raspberry": "5e6ce8", + # size (light green) + "easy": "68fa61", + "weekend": "8efb88", + "hackathon": "c7fdc4", +} + +EXP_BACKUP_EXPONENT = 2 + + +def format_text(text): + parts = text.split("\n\n") + for i, part in enumerate(parts): + preformatted = True + if "\n" in part.strip("\n") and all( + line.startswith(">") for line in part.strip("\n").splitlines()[1:] + ): + preformatted = False + if ( + "\n" not in part.strip() + and part.strip().lower().startswith("on ") + and part.strip().lower().endswith("wrote:") + ): + preformatted = False + if not any( + c in part + for c in ( + "<", + "\\", + "$", + ";", + "|", + "{", + "}", + " ?? ", + "]:", + "(gdb) bt", + ) + ): + preformatted = False + + if preformatted: + parts[i] = textwrap.indent(part, prefix=" ") + else: + # Prevent unintended GH issue links + parts[i] = re.sub(r"#(\d+)", r"#⁠\1", part) + return "\n\n".join(parts) + + +class LaunchpadImporter: + def __init__(self, token, repo, milestonedata, mention): + self.logger = logging.getLogger(__name__) + self.gh = github.Github(login_or_token=token) + self.repo = self.gh.get_repo(repo) + self.gh_labels = { + label.name: label for label in self.repo.get_labels() + } + self.gh_milestones = { + milestone.title: milestone + for milestone in self.repo.get_milestones(state="all") + } + self.lp_milestones = {x["name"]: x for x in milestonedata} + self.mention = mention + + def get_user(self, username): + try: + username = LAUNCHPAD_USER_MAP[username] + if self.mention: + username = "@" + username + else: + # link to profile instead of mention + # to avoid notification/email spam + username = f"[{username}](https://github.com/{username})" + except KeyError: + username = f"[{username}](https://launchpad.net/~{username})" + return username + + def get_label(self, name): + try: + label = self.gh_labels[name] + except KeyError: + label = self.import_label(name) + return label + + def format_body(self, issuedata): + header = [ + f"Reported by: **{self.get_user(issuedata['owner'])}**", + f"Date: {issuedata['date_created']}", + f"Status: {issuedata['status']}", + f"Importance: {issuedata['importance']}", + f"Launchpad Issue: [lp{issuedata['id']}]({issuedata['lp_url']})", + ] + if issuedata["tags"]: + header.append("Tags: %s" % ", ".join(issuedata["tags"])) + if issuedata["attachments"]: + url_strings = [ + f"[{data['title']}]({data['url']})" + for data in issuedata["attachments"] + ] + header.append("Attachments: %s" % ", ".join(url_strings)) + + formatted_text = format_text(issuedata["description"]) + if len(formatted_text.strip()) > 0: + formatted_text = "\n\n---\n\n" + formatted_text + + return "\n".join(header) + formatted_text + + def format_comment(self, commentdata): + header = [ + f"Commented by: **{self.get_user(commentdata['owner'])}**", + f"Date: {commentdata['date_created']}", + ] + if commentdata["attachments"]: + url_strings = [ + f"[{data['title']}]({data['url']})" + for data in commentdata["attachments"] + ] + header.append("Attachments: %s" % ", ".join(url_strings)) + formatted_text = format_text(commentdata["content"]) + if len(formatted_text.strip()) > 0: + formatted_text = "\n\n---\n\n" + formatted_text + return "\n".join(header) + formatted_text + + def name_to_milestone(self, milestone_name): + try: + milestone = self.gh_milestones[milestone_name] + except KeyError: + milestonedata = self.lp_milestones.get( + milestone_name, + { + "active": True, + "date_targeted": None, + "name": milestone_name, + "summary": "", + }, + ) + milestone = self.import_milestone(milestonedata) + return milestone + + def handle_ratelimit(self, func): + abuse_timeout = 30 + while True: + try: + return func() + except github.RateLimitExceededException: + rate_limit_resettime = datetime.datetime.utcfromtimestamp( + self.gh.rate_limiting_resettime + ) + self.logger.warning( + "Rate limit exceeded (%d left/%d total), waiting until %s", + *self.gh.rate_limiting, + rate_limit_resettime.isoformat(), + ) + seconds_to_wait = ( + rate_limit_resettime - datetime.datetime.now() + ).total_seconds() + if seconds_to_wait <= 0: + self.logger.warning( + "Failed to detect wait time, assuming 10 seconds..." + ) + seconds_to_wait = 10 + self.logger.warning("Sleeping for %d seconds", seconds_to_wait) + time.sleep(seconds_to_wait) + except github.GithubException as e: + if e.status == 403 and "abuse" in e.data.get("message", ""): + self.logger.warning( + "Triggered abuse detection, sleeping %d seconds...", + abuse_timeout, + ) + time.sleep(abuse_timeout) + abuse_timeout *= EXP_BACKUP_EXPONENT + elif e.status == 403 and "secondary rate limit" in e.data.get( + "message", "" + ): + abuse_timeout = e.headers.get("Retry-After", abuse_timeout) + self.logger.warning( + "Triggered secondary rate limit, " + "sleeping %d seconds...", + abuse_timeout, + ) + time.sleep(abuse_timeout) + abuse_timeout *= EXP_BACKUP_EXPONENT + elif e.status in range(500, 600): + self.logger.warning( + f"Internal server Error, sleeping {abuse_timeout} " + f"seconds and retrying" + ) + self.logger.warning(e) + time.sleep(abuse_timeout) + abuse_timeout *= EXP_BACKUP_EXPONENT + else: + raise + else: + break + + def import_milestone(self, milestonedata): + state = "open" if milestonedata["active"] else "closed" + due_on = github.GithubObject.NotSet + if milestonedata["date_targeted"]: + due_on = datetime.datetime.strptime( + milestonedata["date_targeted"], "%Y-%m-%dT%H:%M:%SZ" + ) + description = github.GithubObject.NotSet + if milestonedata["summary"]: + description = milestonedata["summary"] + milestone = self.handle_ratelimit( + lambda: self.repo.create_milestone( + milestonedata["name"], state, description, due_on + ) + ) + self.logger.info("Created milestone: %r", milestone) + self.gh_milestones[milestone.title] = milestone + return milestone + + def status_to_label(self, status): + for label_name in LAUNCHPAD_STATUS_MAP.get(status, []): + yield self.get_label(label_name) + + def importance_to_label(self, importance): + for label_name in LAUNCHPAD_IMPORTANCE_MAP.get(importance, []): + yield self.get_label(label_name) + + def import_label(self, label_name): + color = LABELS.get(label_name, None) + if not color: + color = "{c}{c}{c}".format( + c=binascii.hexlify(random.randbytes(1)).decode() + ) + label = self.handle_ratelimit( + lambda: self.repo.create_label(label_name, color) + ) + self.logger.info("Created label: %r", label) + self.gh_labels[label_name] = label + return label + + def name_to_assignee(self, name): + username = LAUNCHPAD_USER_MAP.get(name) + if username and username in GITHUB_ALLOWED_ASSIGNEES: + return username + else: + return github.GithubObject.NotSet + + def import_issue(self, issuedata): + milestone = github.GithubObject.NotSet + if issuedata["milestone"]: + milestone = self.name_to_milestone(issuedata["milestone"]) + labels = [] + labels.extend(self.status_to_label(issuedata["status"])) + labels.extend(self.importance_to_label(issuedata["importance"])) + if issuedata["duplicate_of"]: + labels.append(self.get_label("duplicate")) + if issuedata["security_related"]: + labels.append(self.get_label("security")) + if issuedata["tags"]: + labels.extend( + [ + self.get_label(tag) + for tag in issuedata["tags"] + if tag in LABELS + ] + ) + assignee = self.name_to_assignee(issuedata["assignee"]) + # todo upload attachments here + issue = self.handle_ratelimit( + lambda: self.repo.create_issue( + title=issuedata["title"], + body=self.format_body(issuedata), + milestone=milestone, + assignee=assignee, + labels=labels, + ) + ) + self.logger.info("Created issue: %r", issue) + return issue + + def import_issuecomment(self, issue, commentdata): + comment = self.handle_ratelimit( + lambda: issue.create_comment(self.format_comment(commentdata)) + ) + self.logger.info("Created issue comment: %r", comment) + return comment + + # TODO handing duplicates is broken again. pls fix + + def run_import(self, lp_issues, lp_milestones): + num_issues = len(lp_issues.values()) + for i, issuedata in enumerate( + sorted( + lp_issues.values(), key=lambda x: (x["date_created"], x["id"]) + ), + 1, + ): + gh_issue_number = issuedata.get("gh_issue_number") + if gh_issue_number: + if issuedata.get("gh_comments_imported") == len( + issuedata["comments"] + ) and issuedata.get("gh_status_comment_imported", False): + continue + + issue = self.handle_ratelimit( + lambda: self.repo.get_issue(gh_issue_number) + ) + else: + issue = self.import_issue(issuedata) + lp_issues[issuedata["id"]]["gh_issue_number"] = issue.number + + comments_imported = issuedata.get("gh_comments_imported", 0) + lp_issues[issuedata["id"]][ + "gh_comments_imported" + ] = comments_imported + + comments = issuedata["comments"][comments_imported:] + for comment in comments: + comment = self.import_issuecomment(issue, comment) + lp_issues[issuedata["id"]]["gh_comments_imported"] += 1 + + if issuedata.get("gh_status_comment_imported", False): + continue + + if issuedata["status"] in ( + "Fix Released", + "Fix Committed", + "Invalid", + "Won't Fix", + ): + comment = ( + f'Issue closed with status **{issuedata["status"]}**.' + ) + self.handle_ratelimit(lambda: issue.create_comment(comment)) + if issue.state != "closed": + self.handle_ratelimit(lambda: issue.edit(state="closed")) + lp_issues[issuedata["id"]]["gh_status_comment_imported"] = True + self.logger.info( + f"Imported {i}/{num_issues} " + f"({'{:.2f}'.format((i/num_issues)*100)}%)" + ) + + for issuedata in sorted( + lp_issues.values(), key=lambda x: (x["date_created"], x["id"]) + ): + if issuedata.get("gh_duplicate_comment_imported", False): + continue + + duplicate_of = issuedata.get("duplicate_of") + + if duplicate_of is not None: + duplicate_issue_number = lp_issues[issuedata["id"]][ + "gh_issue_number" + ] + original = lp_issues[duplicate_of]["gh_issue_number"] + self.logger.info( + f"Marking #{duplicate_issue_number} " + f"as duplicate of #{original}" + ) + + issue = self.handle_ratelimit( + lambda: self.repo.get_issue(duplicate_issue_number) + ) + comment = f"Duplicate of #{original}" + self.handle_ratelimit(lambda: issue.create_comment(comment)) + if issue.state != "closed": + self.handle_ratelimit(lambda: issue.edit(state="closed")) + lp_issues[issuedata["id"]]["gh_duplicate_comment_imported"] = True + + self.logger.info(f"Successfully imported {num_issues} issues") + + +def main(argv=None): + parser = argparse.ArgumentParser() + parser.add_argument("--repo", required=True) + parser.add_argument("--token", required=True) + parser.add_argument("--output-file") + parser.add_argument( + "--mention", default=False, action=argparse.BooleanOptionalAction + ) + parser.add_argument("bugs_file", type=argparse.FileType("r")) + parser.add_argument("milestone_file", type=argparse.FileType("r")) + args = parser.parse_args(argv) + + logging.basicConfig( + format="%(asctime)s %(levelname)-8s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.INFO, + ) + + lp_milestones = json.load(args.milestone_file) + lp_issues = {x["id"]: x for x in json.load(args.bugs_file)} + importer = LaunchpadImporter( + args.token, args.repo, lp_milestones, args.mention + ) + import_start = datetime.datetime.utcnow() + try: + importer.run_import(lp_issues, lp_milestones) + finally: + logging.info( + f"Import took {datetime.datetime.utcnow() - import_start}" + ) + if args.output_file: + with open(args.output_file, mode="w") as f: + json.dump(list(lp_issues.values()), f) + + +if __name__ == "__main__": + main() From 1e0dc0a4e56f77ba248292059a806a9396e0aea0 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Wed, 3 Aug 2022 23:26:14 +0200 Subject: [PATCH 67/75] fix(tools): fix json2github.py not respecting RateLimit timeout This was due to mistakes in the calculation for the wait time which arose because of improper handling of timezones. --- tools/json2github.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/json2github.py b/tools/json2github.py index 7dc8c9083da..a007985baa6 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -414,7 +414,7 @@ def handle_ratelimit(self, func): rate_limit_resettime.isoformat(), ) seconds_to_wait = ( - rate_limit_resettime - datetime.datetime.now() + rate_limit_resettime - datetime.datetime.utcnow() ).total_seconds() if seconds_to_wait <= 0: self.logger.warning( From 3684a29ee0562eb24c5bd6c50a8f7511ff59104a Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:37:31 +0200 Subject: [PATCH 68/75] fix(tools): json2github handle bugs outside mixxx Issues can be duplicates of of issues that don't belong to the mixxx project. Since those are obviously not imported to github, we link to their originals on launchpad instead of github. --- tools/json2github.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tools/json2github.py b/tools/json2github.py index a007985baa6..298e45727dc 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -609,16 +609,27 @@ def run_import(self, lp_issues, lp_milestones): duplicate_issue_number = lp_issues[issuedata["id"]][ "gh_issue_number" ] - original = lp_issues[duplicate_of]["gh_issue_number"] + + original = lp_issues.get(duplicate_of) + if original is None: + # Bug this is marked as a duplicate of does not + # belong to mixxxx + # so link to the original on launchpad + original = ( + f"[lp:{duplicate_of}]" + f"(https://bugs.launchpad.net/bugs/{duplicate_of})" + ) + else: + original = f"#{original['gh_issue_number']}" self.logger.info( f"Marking #{duplicate_issue_number} " - f"as duplicate of #{original}" + f"as duplicate of {original}" ) issue = self.handle_ratelimit( lambda: self.repo.get_issue(duplicate_issue_number) ) - comment = f"Duplicate of #{original}" + comment = f"Duplicate of {original}" self.handle_ratelimit(lambda: issue.create_comment(comment)) if issue.state != "closed": self.handle_ratelimit(lambda: issue.edit(state="closed")) From 3199ab496832dc21fc3c630237d1a209c2d31c4a Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Thu, 4 Aug 2022 22:32:36 +0200 Subject: [PATCH 69/75] feat(tools): tool to fix issue-json after transfer Since issues get a new ID/number during bulk-transfer we need to update our launchpad-export-json with the new numbers. This is done via a mapping file we get from githubs bulk-transfer tools. --- tools/transfer_issue_mapping.py | 83 +++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 tools/transfer_issue_mapping.py diff --git a/tools/transfer_issue_mapping.py b/tools/transfer_issue_mapping.py new file mode 100755 index 00000000000..34fdf0ffd49 --- /dev/null +++ b/tools/transfer_issue_mapping.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +""" +Complementary tool to json2github.py + +When bulk-transfering issues between repositories using githubs +internal bulk-transfer tools. The generate CSV file containing +a mapping from source to destination URL. +This tool updates the state serialized state of json2github.py +(specified via the json2github --output-file flag) from the +pre-transfer issue numbers to the new issue numbers, specified +by the mapping file we received from github. + +This tool only maps issue ID's and assumes all the source issues +and all the destination issues belong to the same repo. + +According to people from github, the format they use is a CSV +table with the source URL in the 0th column and the destination +URL in the 1st column + +""" + +import argparse +import urllib.parse +import csv +import json + +import sys + + +def eprint(str): + print(str, file=sys.stderr) + + +def issue_nr_from_url(url): + path_segments = urllib.parse.urlparse(url).path.split("/") + assert path_segments[-2].startswith("issue") + return int(path_segments[-1]) + + +def make_mapping(id_mappings_csv): + csv_reader = csv.DictReader( + id_mappings_csv, fieldnames=("source", "destination") + ) + return { + issue_nr_from_url(line["source"]): issue_nr_from_url( + line["destination"] + ) + for line in csv_reader + } + + +def fixup_ids(lp_issues, mapping): + for issue in lp_issues: + num = issue.get("gh_issue_number") + if num is None: + eprint( + f"issue {issue['id']} has not been " + f"imported to github, skipping!" + ) + continue + issue["gh_issue_number"] = mapping[num] + + +def main(argv=None): + parser = argparse.ArgumentParser() + parser.add_argument("--mapping_file", type=argparse.FileType("r")) + parser.add_argument("--lp_issues_file", type=argparse.FileType("r")) + parser.add_argument("--output_file", type=argparse.FileType("w")) + args = parser.parse_args(argv) + + mapping_file = args.mapping_file + lp_issues = json.load(args.lp_issues_file) + + mapping = make_mapping(mapping_file) + print(mapping) + + fixup_ids(lp_issues, mapping) + + json.dump(lp_issues, args.output_file) + + +if __name__ == "__main__": + main() From 302a138236c8f00d43c6c0f3dc17f29e8e59a6d1 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Thu, 4 Aug 2022 22:33:55 +0200 Subject: [PATCH 70/75] feat(tools): json2github handle milestones fixup [WIP] --- tools/json2github.py | 33 ++++++++++++++++++++++++++++----- tools/transfer_issue_mapping.py | 13 +++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/tools/json2github.py b/tools/json2github.py index 298e45727dc..cd6034bb11d 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -542,8 +542,6 @@ def import_issuecomment(self, issue, commentdata): self.logger.info("Created issue comment: %r", comment) return comment - # TODO handing duplicates is broken again. pls fix - def run_import(self, lp_issues, lp_milestones): num_issues = len(lp_issues.values()) for i, issuedata in enumerate( @@ -554,14 +552,37 @@ def run_import(self, lp_issues, lp_milestones): ): gh_issue_number = issuedata.get("gh_issue_number") if gh_issue_number: - if issuedata.get("gh_comments_imported") == len( - issuedata["comments"] - ) and issuedata.get("gh_status_comment_imported", False): + + issue_milestone = issuedata["milestone"] + + if ( + issuedata.get("gh_comments_imported") + == len(issuedata["comments"]) + and issuedata.get("gh_status_comment_imported", False) + and issue_milestone is None + ): continue issue = self.handle_ratelimit( lambda: self.repo.get_issue(gh_issue_number) ) + # fixup milestone ownership in case it got lost + # (happens during bulk issue transfer between repos using + # githubs internal tools) + if issue_milestone is not None: + milestone = self.name_to_milestone(issue_milestone) + if issue.milestone != milestone: + self.logger.info( + f"fixing up milestone " + f'"{issue_milestone}" for ' + f"issue #{gh_issue_number}" + ) + # issue on launchpad is attached to milestone + # but corresponding pre-existing issue on gh does not + # have the milestone. Attach it here. + self.handle_ratelimit( + lambda: issue.edit(milestone=milestone) + ) else: issue = self.import_issue(issuedata) lp_issues[issuedata["id"]]["gh_issue_number"] = issue.number @@ -584,6 +605,8 @@ def run_import(self, lp_issues, lp_milestones): "Fix Committed", "Invalid", "Won't Fix", + "Expired", + "Incomplete", ): comment = ( f'Issue closed with status **{issuedata["status"]}**.' diff --git a/tools/transfer_issue_mapping.py b/tools/transfer_issue_mapping.py index 34fdf0ffd49..45145f7fec3 100755 --- a/tools/transfer_issue_mapping.py +++ b/tools/transfer_issue_mapping.py @@ -63,16 +63,21 @@ def fixup_ids(lp_issues, mapping): def main(argv=None): parser = argparse.ArgumentParser() - parser.add_argument("--mapping_file", type=argparse.FileType("r")) - parser.add_argument("--lp_issues_file", type=argparse.FileType("r")) - parser.add_argument("--output_file", type=argparse.FileType("w")) + parser.add_argument( + "--mapping_file", type=argparse.FileType("r"), required=True + ) + parser.add_argument( + "--lp_issues_file", type=argparse.FileType("r"), required=True + ) + parser.add_argument( + "--output_file", type=argparse.FileType("w"), required=True + ) args = parser.parse_args(argv) mapping_file = args.mapping_file lp_issues = json.load(args.lp_issues_file) mapping = make_mapping(mapping_file) - print(mapping) fixup_ids(lp_issues, mapping) From 690e30c3e9266c7850fb07b9b10e0d208caa6ef0 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Tue, 16 Aug 2022 20:27:53 +0200 Subject: [PATCH 71/75] improve log output when github ratelimit exceeded --- tools/json2github.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/json2github.py b/tools/json2github.py index cd6034bb11d..9015ed7d049 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -413,16 +413,16 @@ def handle_ratelimit(self, func): *self.gh.rate_limiting, rate_limit_resettime.isoformat(), ) - seconds_to_wait = ( + time_to_wait = ( rate_limit_resettime - datetime.datetime.utcnow() - ).total_seconds() - if seconds_to_wait <= 0: + ) + if time_to_wait.total_seconds() <= 0: self.logger.warning( "Failed to detect wait time, assuming 10 seconds..." ) - seconds_to_wait = 10 - self.logger.warning("Sleeping for %d seconds", seconds_to_wait) - time.sleep(seconds_to_wait) + time_to_wait = datetime.timedelta(seconds=10) + self.logger.warning(f"Sleeping for {time_to_wait}") + time.sleep(time_to_wait.total_seconds()) except github.GithubException as e: if e.status == 403 and "abuse" in e.data.get("message", ""): self.logger.warning( From d625b660a5af7bc5d1d8c4c1346b210a408aed32 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Tue, 16 Aug 2022 20:32:17 +0200 Subject: [PATCH 72/75] dedup code --- tools/json2github.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/json2github.py b/tools/json2github.py index 9015ed7d049..6ad1c4291aa 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -401,6 +401,12 @@ def name_to_milestone(self, milestone_name): def handle_ratelimit(self, func): abuse_timeout = 30 + + def sleep_exp_backoff(): + nonlocal abuse_timeout + time.sleep(abuse_timeout) + abuse_timeout *= EXP_BACKUP_EXPONENT + while True: try: return func() @@ -429,8 +435,7 @@ def handle_ratelimit(self, func): "Triggered abuse detection, sleeping %d seconds...", abuse_timeout, ) - time.sleep(abuse_timeout) - abuse_timeout *= EXP_BACKUP_EXPONENT + sleep_exp_backoff() elif e.status == 403 and "secondary rate limit" in e.data.get( "message", "" ): @@ -440,16 +445,14 @@ def handle_ratelimit(self, func): "sleeping %d seconds...", abuse_timeout, ) - time.sleep(abuse_timeout) - abuse_timeout *= EXP_BACKUP_EXPONENT + sleep_exp_backoff() elif e.status in range(500, 600): self.logger.warning( f"Internal server Error, sleeping {abuse_timeout} " f"seconds and retrying" ) self.logger.warning(e) - time.sleep(abuse_timeout) - abuse_timeout *= EXP_BACKUP_EXPONENT + sleep_exp_backoff() else: raise else: From 91a33e26e2c19fd14f78c5dec0449089c507430d Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Tue, 16 Aug 2022 20:42:30 +0200 Subject: [PATCH 73/75] retry on connection errors --- tools/json2github.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/json2github.py b/tools/json2github.py index 6ad1c4291aa..c31dec35699 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -33,6 +33,7 @@ import textwrap import time import github +import requests LAUNCHPAD_STATUS_MAP = { "Confirmed": ["confirmed"], @@ -455,6 +456,12 @@ def sleep_exp_backoff(): sleep_exp_backoff() else: raise + except requests.exceptions.ConnectionError as e: + self.logger.warning(e) + self.logger.warning( + "encountered connection error, retrying..." + ) + sleep_exp_backoff() else: break From 03f4efbc42f76095d2ebe6d5342a95c48d28e508 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Tue, 16 Aug 2022 20:45:43 +0200 Subject: [PATCH 74/75] improve logging in resume logic --- tools/json2github.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/json2github.py b/tools/json2github.py index c31dec35699..2d9cd714b75 100644 --- a/tools/json2github.py +++ b/tools/json2github.py @@ -573,6 +573,10 @@ def run_import(self, lp_issues, lp_milestones): ): continue + self.logger.info( + f"checking if issue #{gh_issue_number} requires fixup" + ) + issue = self.handle_ratelimit( lambda: self.repo.get_issue(gh_issue_number) ) From d1133401dc7cd243ff47a7a05e89c07a063a8b7f Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Sun, 9 Oct 2022 14:54:20 +0200 Subject: [PATCH 75/75] add backlinking script --- tools/backlink_launchpad_bugs_to_github.py | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tools/backlink_launchpad_bugs_to_github.py diff --git a/tools/backlink_launchpad_bugs_to_github.py b/tools/backlink_launchpad_bugs_to_github.py new file mode 100644 index 00000000000..6245e96f6c2 --- /dev/null +++ b/tools/backlink_launchpad_bugs_to_github.py @@ -0,0 +1,61 @@ +# /usr/bin/env python3 + +import argparse +import json +import logging +from launchpadlib.launchpad import Launchpad + + +def gh_issue_to_commenttext(issue): + return ( + f"Mixxx now uses GitHub for bug tracking. " + f"This bug has been migrated to: \n" + f"https://github.com/mixxxdj/mixxx/issues/{issue}" + ) + + +def main(argv=None): + parser = argparse.ArgumentParser() + parser.add_argument("bugs_file", type=argparse.FileType("r")) + parser.add_argument("--output-file") + args = parser.parse_args(argv) + + logging.basicConfig( + format="%(asctime)s %(levelname)-8s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.INFO, + ) + + lp_issues = {x["id"]: x for x in json.load(args.bugs_file)} + + # This will open up a web-browser to do OAuth authentication, so + # you need a GUI and webbrowser so this authentication works. + launchpad = Launchpad.login_with( + "Mixxx Issue Migration Backlinks", + "production", # change me to 'production'/'staging' when ready + version="devel", + ) + try: + for i, issuedata in enumerate( + sorted( + lp_issues.values(), key=lambda x: (x["date_created"], x["id"]) + ), + 1, + ): + if issuedata.get("lp_backlink_imported"): + continue + + lp_issue = launchpad.bugs[issuedata["id"]] + print(lp_issue) + msg_content = gh_issue_to_commenttext(issuedata["gh_issue_number"]) + lp_issue.newMessage(content=msg_content, send_notifications=False) + lp_issue.lock(status="Comment-only") + issuedata["lp_backlink_imported"] = True + finally: + if args.output_file: + with open(args.output_file, mode="w") as f: + json.dump(list(lp_issues.values()), f) + + +if __name__ == "__main__": + main()