Skip to content

Update Mixtrack (Pro) 3 mappings for Mixxx 2.1#1180

Merged
daschuer merged 83 commits intomixxxdj:masterfrom
radusuciu:master
Mar 25, 2017
Merged

Update Mixtrack (Pro) 3 mappings for Mixxx 2.1#1180
daschuer merged 83 commits intomixxxdj:masterfrom
radusuciu:master

Conversation

@radusuciu
Copy link
Copy Markdown
Contributor

@radusuciu radusuciu commented Feb 10, 2017

This is a WIP, not quite ready for review since I haven't had time to actually test it. Opening pull request a bit early just to move discussion from #1014. First time contributor so please let me know if I'm going against the grain!

To-do:

  • Load sample if none is currently loaded
  • Make use of focused_effect
  • Map sampler eject
  • Look at bpm tap functionality, which I either broke, or is broken

// NMTP3 is a "Model A" controller for scratching, it centers on 0.
// See http://www.mixxx.org/wiki/doku.php/midi_scripting#scratching
// and see "Jogger" object constructor
this.beatJumpSize = 1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, this will be available as a ControlObject that will also be shown on skins so controller scripts won't have to keep track of this. I might implement that for Mixxx 2.2. There is a Launchpad ticket tracking it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be awesome. I will not be committing code that will modify this value until the CO will be there as this controller has no way of displaying it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may find a beatjump size of 4 beats to be more helpful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I just tried to install Mixxx 2.1 on Windows 10 and the installer failed. Also, I got 3 different warnings asking to confirm that I wanted to install the package; the first one saying that Windows did not recommend installing it, likely because package was not signed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Windows 10 you have to click "More Info" and then tell it you really mean to install it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please report a bug for that.

@radusuciu
Copy link
Copy Markdown
Contributor Author

Will the new effects interface be used across all skins? There is currently a lot of code duplication as a result of having to support skins that have only one effect per rack. Documented here:

// Effects mode
// 1 for multi-effect mode (3 effects controlled in each EffectUnit, best used with Deere Skin)
// 2 for single effect mode (1 effect controlled in each EffectUnit, best used with skins other than Deere)
var FXmode = 1; // multi-effect mode by default

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Feb 10, 2017

Will the new effects interface be used across all skins?

Yes, that's part of the point. Controller mappings having different options for different skins is a really ugly situation.

@radusuciu
Copy link
Copy Markdown
Contributor Author

Awesome, thank you. 👍

}

for (i = engine.getValue("[Master]", "num_decks"); i >= 1; i--) {
for (var i = engine.getValue("[Master]", "num_decks"); i >= 1; i--) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, in the old version of JS that Mixxx still uses (and in modern JS using var), variables are scoped to functions, not blocks as you might expect. You don't need to redeclare i for each loop. Just something to be aware of if you encounter puzzling bugs with one loop messing up the behavior of the next.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aware that JS lacks block scoping when using var, and that variable declarations get hoisted, but I think pretty much everyone except Crockford will advocate for including var in for loops.

As an aside, the mapping in its current state is not functional since I committed stuff without having the controller on hand. I will go back and test things commit by commit though!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, just pointing it out because many people who contribute mapping scripts aren't that familiar with JS.

@radusuciu
Copy link
Copy Markdown
Contributor Author

@djsteph Just came across this: https://docs.google.com/spreadsheets/d/1YbLS7hBprP2uvEKizO-b0WiaRmpvml0r5NfBp4GmBVc/edit#gid=0

I'm guessing it was most useful during development but I think I'd like to use it as well. It will make a fantastic quality check for the mapping.

@djsteph
Copy link
Copy Markdown
Contributor

djsteph commented Feb 10, 2017 via email

@radusuciu
Copy link
Copy Markdown
Contributor Author

radusuciu commented Feb 14, 2017

Trying to debug things and getting a billion messages of this nature:

Note that none of the buttons on the controller are flashing, but the messages keep pouring in.

Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 184549449 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 268435486 
Debug [Controller]: Killing timer: 184549449 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: Killing timer: 268435486 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x00" 

Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 1493172255 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 1509949470 
Debug [Controller]: Killing timer: 1493172255 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: Killing timer: 1509949470 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x00" 

Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 805306398 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 922746911 

Debug [Controller]: Killing timer: 805306398 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: Killing timer: 922746911 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 1811939393 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 1912602654 

Debug [Controller]: Killing timer: 1811939393 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: Killing timer: 1912602654 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x92 (ch 3, opcode 0x9), ctrl 0x13, val 0x00" 
Debug [Controller]: "MixTrack Pro 3: outgoing: status 0x91 (ch 2, opcode 0x9), ctrl 0x13, val 0x20" 
Debug [Controller]: Starting one-shot timer: 1660944414 

Is this normal?

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Feb 14, 2017

Yes, that is normal. I added outgoing MIDI debugging messages in #1004. Is that an issue? Would you like an option to only see incoming MIDI?

@radusuciu radusuciu force-pushed the master branch 2 times, most recently from 3925289 to 38ed3f2 Compare February 14, 2017 09:55
@radusuciu
Copy link
Copy Markdown
Contributor Author

radusuciu commented Feb 14, 2017

Well, it kind of makes it difficult to debug by logging things with print statements since anything you log gets drowned out very quickly by messages from permanent timers.

Perhaps I'm doing debugging wrong? These are the options I am using:

--developer --debugLevel 2 --controllerDebug --resourcePath "%USERPROFILE%/Github/mixxx/res"

Thank you for your help!

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Feb 14, 2017

--debugLevel was recently renamed to --logLevel (#1159), so that does not do anything currently, but --developer automatically sets logLevel to debug unless otherwise specified. Try running with --logLevel debug without --controllerDebug. That might hide the MIDI debugging messages but still let scripts print to the console output.

contract = 0;
}

if (shifted && value === ON) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, you are not keeping the maximize library on the browse button push? In this code sniplet, I don't see any value set for LibraryGroup and Library command nor do I see the actual change in the code to remove the variable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was an oversight - thanks for noticing. Will fix.

@radusuciu radusuciu force-pushed the master branch 2 times, most recently from 8cadac0 to 84edb44 Compare February 15, 2017 17:36
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few quick comments

* the same tempo, and decks that also have quantize
* enabled will always have their beats lined up.
* If the Sync Loack was previously activated, it just desactivate it,
* If Sync Lock was previously activated, it just desactivate it,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "deactivate"

} else {
// play sampler with Sync
engine.setValue(group, "cue_gotoandplay", 1);
engine.setValue(group, "beatsync", 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You removed the comment about playing with sync. Did you mean to remove the syncing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I just thought the code is pretty clear in this case. Shift + Sampler will play the sample without sync so it's pretty easy to switch between the two.

Earlier I thought there'd be an issue with mapping Shift + Sampler to stop a sample, but there isn't one since stopping is only done on playing samples and playing without sync is only done on non-playing samples.

<MixxxControllerPreset mixxxVersion="2.1.0+" schemaVersion="1">
<info>
<name>Numark Mixtrack (Pro) 3</name>
<author>Stéphane Morin</author>
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing Mar 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to mention yourself here (Keep Stéphane's name too).

Copy link
Copy Markdown
Contributor

@Be-ing Be-ing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow that was a lot of code changed! Thanks for the cleanup. I found a handful of other places in the diff where the code could be cleaned up a little bit plus a few UX suggestions. Looks almost ready to merge.

// fastSeekEnabled: enable fast seek with Jog Wheel with Wheel Off and Shift ON
// Shift can be locked or not
var fastSeekEnabled = true;

//activate PFL of deck on track load
var smartPFL = true;

// use beatlooproll instead of beatloop
var beatlooprollActivate = false;
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing Mar 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option could be removed by following the behavior of the new loopauto_toggle CO in #1187: normal loops for loops > 1 beat; rolling loops for loops <= 1 beat. That matches how the loop sizes are mapped to the pads in this. Normal loops without shift; rolling loops with shift.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think those behaviours are the same, this option makes it so that all the loops set with the auto loop buttons are rolling. Also, the Shift behaviour isn't to toggle loopRoll, but rather to allow for the toggling of fractional beat loops (mapping 4 buttons to 8 loop sizes).

I understand your suggestion but I'm not quite sure if I want all of my <= 1 beat loops to be rolling. Will consider it, especially if others want the shifted behaviour you describe.

For now, I will remove the option since I can't imagine anyone wanting all of their loops to be rolling, especially without a way to toggle. Will be revisiting this when #1187 is merged.

Copy link
Copy Markdown
Contributor

@Be-ing Be-ing Mar 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use of loops <= 1 beat that aren't rolling? Play with it, I think you'll find my suggestion makes sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Say instead of rolling into a drop on the same track, you bring in another track instead, and you want to leave the other track where it is instead of having it slip past when you stop the loop.

I suppose there are other ways around that though..

});
// permanent timer
this.flashTimer = engine.beginTimer(num_ms_on + num_ms_off, function() {
myself.flashOnceOn(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get rid of this hacky closure and use this directly since #1196 was merged.

Copy link
Copy Markdown
Contributor Author

@radusuciu radusuciu Mar 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this:

engine.beginTimer(num_ms_on + num_ms_off, 'this.flashOnceOn(false)');

preferred over:

engine.beginTimer(num_ms_on + num_ms_off, this.flashOnceOn.bind(this, false));

I get that I don't need to bind for this but I also have an argument I'd like to curry. Most examples I've seen use the string method but I feel like the latter is better practice.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the ability to pass strings instead of functions is an ugly hack that shouldn't have been implemented in the first place. I think this form would be best:

engine.beginTimer(num_ms_on + num_ms_off, function () {
    this.flashOnceOn(false);
});

if (flashCount > 1) {
// flashcount>0 , means temporary flash, first flash already done,
// so we don't need this part if flashcount=1
// temporary timer. The end of this timer stops the permanent flashing

this.flashTimer2 = engine.beginTimer(flashCount * (num_ms_on +
num_ms_off) - num_ms_off, function() {
this.flashTimer2 = engine.beginTimer(flashCount * (num_ms_on + num_ms_off) - num_ms_off, function() {
myself.Stopflash(relight);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this

myself.flashOnceOff(relight);
}, true);
this.flashOnceTimer = engine.beginTimer(this.num_ms_on - scriptpause, function() {
myself.flashOnceOff(relight);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this

}, true);
if (this.ButtonTimer === 0) { // first press
this.ButtonTimer = engine.beginTimer(this.DoublePressTimeOut, function() {
myself.ButtonDecide();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this

Copy link
Copy Markdown
Contributor Author

@radusuciu radusuciu Mar 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to my question above.

engine.beginTimer(this.DoublePressTimeOut, 'this.ButtonDecide()');

vs.

engine.beginTimer(this.DoublePressTimeOut, this.ButtonDecide);

here I assume that bind isn't necessary at all since we're not going to pass any parameters.

} else {
// Else play/pause
toggleValue("[Channel" + decknum + "]", "play");
// else play/pause
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, no explanation needed.

if (!deck.TrackIsLoaded()) {
// If a track is not loaded, load the selected track (if any) and play
engine.setValue("[Channel" + decknum + "]", "LoadSelectedTrackAndPlay", true);
// if a track is not loaded, load the selected track (if any) and play
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this code is self explanatory and doesn't need a comment.

} else if (deck.shiftKey && value === DOWN) {
// load next effect and make sure the unit is enabled
engine.setValue(effectGroup, "next_effect", true);
engine.setValue("[EffectRack1_EffectUnit" + decknum + "]", "group_[Channel" + decknum + "]_enable", true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this line should be removed. It may have made sense with the old mapping, but I don't think it makes sense to couple it to switching one effect in the chain.

for (i = 1; i <= 4; i++) {
var deck = NumarkMixtrack3.deckFromGroup(group);
// beat knobs sends 1 or 127 as value. If value = 127, turn is counterclockwise
var increase = (value !== 127);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think var increase = (value === 1); would be clearer.

var decknum = script.deckFromGroup(group);
var deck = NumarkMixtrack3.decks["D" + decknum];
if (deck.loaded && TrackEndWarning) {
var timeremaining = duration * (1 - value);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inconsistent capitalization of variable name

}, true);

this.ButtonLongPressTimer = engine.beginTimer(
this.LongPressThreshold, this.ButtonAssertLongPress, true
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing Mar 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think this actually would have worked in Mixxx 2.0. What #1196 fixed was using this inside the callback function. For example: fd9815d

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, the ButtonAssertLongPress function refers to this, so maybe it wouldn't have worked. Anyway, looks good now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, just figured there's little point in wrapping it with a function if no arguments need to be passed.

"hotCue3": 0x1d,
"hotCue4": 0x1e,
"Cue": 0x03,
"cue": 0x03,
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing Mar 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, if you forget something in a commit and haven't added any new commits yet, git commit --amend is an easy way to overwrite the incomplete commit. It's no big deal you didn't do that here, but something to keep in mind if you are in that situation again.

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Mar 10, 2017

Alright this looks good to me! 👍 Thank you! I'm glad one of the best selling controllers on the market right now will have a good mapping for the new effects UI for the 2.1 release. :)

After #1187 is merged you may want to reconsider how loops are mapped, but I've been careful to make sure that old mappings will still work with the new looping interface.

@radusuciu
Copy link
Copy Markdown
Contributor Author

Thanks! I want to do a final test before merge so as to not have to open another PR just for minor fixes.

I will follow up with a PR for #1187 and #940 in the near future.

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Mar 10, 2017

If you'd like to play with those before they're merged, you can checkout PRs locally and build them. I put some tips on the wiki for using git worktree to play with experimental skins and mappings.

Conflict with InstantFX
120 goes into red way too easily. 82 was juuuust right.
@radusuciu
Copy link
Copy Markdown
Contributor Author

Good to go from my end with these minor fixes. Effect units definitely need to be reworked though, will try and see if I can get a build going as you described.

Thanks for review and hand-holding!

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Mar 18, 2017

Could someone merge this?

I do not know if you are on the mailing list, but I just wrote a proposal for registering MIDI inputs from JS. Feedback would be appreciated.

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Mar 25, 2017

@daschuer can you merge this?

@daschuer
Copy link
Copy Markdown
Member

Yo! Thank your for the work.

@daschuer daschuer merged commit e9f2d97 into mixxxdj:master Mar 25, 2017
@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Jun 6, 2017

@radusuciu, now that #1187 and #940 have been merged, could you update this for the new looping and beatjumping Controls? I suggest remapping the autoloop pad layer similar to the Pioneer DDJ-SB2. Users have been reporting that mapping pads that way is a little strange at first but great after getting used to it. Unlike the DDJ-SB2, because there are other parts of the controller that could be used for beatjumping, I think it would make more sense to use beatjump_1_backward/forward as the shift action for loop halve/double. You could use shift + pitch bend buttons to halve/double beatjump_size and shift + Beats encoder for beatjump_backward/forward.

Also, when I played with a DDJ-SB2, I found it was more helpful to have quick access to changing the focused effect than toggling the effect enable switches. I suggest switching these around in the Mixtrack Pro 3 mapping, so pressing the effect buttons changes the focused effect and Tap + effect button toggles the effect enable switches.

@radusuciu
Copy link
Copy Markdown
Contributor Author

Yep, I will update it to make use of the new controls and will consider your mapping suggestions. I've also done a bit of playing with your components lib so can maybe bring in EffectUnit to start.

@Be-ing
Copy link
Copy Markdown
Contributor

Be-ing commented Jun 6, 2017

The EffectUnit object from the Components library is made for controllers with 4 effects knobs, so adapting it for the Mixtrack Pro 3 would probably be just as much (or maybe more) work than writing the code from scratch. However, using the Components and ComponentContainer objects to write an EffectUnit object specific to this controller would make sense if you'd like to rewrite the code you already have.

I don't recommend copying how the effects buttons work with the DDJ-SB2 in #1243. I used short versus long button presses to distinguish between switching focus and enabling effects, which is a bit clumsy because the script has to wait for the button to be released before switching the focus. There also isn't a way to show which effects are enabled on the controller. These don't need to be issues with the Mixtrack Pro 3 because the Tap button can be used to switch layers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants