Reloop Mixtour: initial implementation - #15790
Conversation
added feature for Back button to toggle display of maximized Library
acolombier
left a comment
There was a problem hiding this comment.
Small nit regarding the use of the midi-components's connections list. For context, this array stores active connection, so upon disconnect, you should remove it, instead of undefining it
Looks good otherwise, though haven't tested it!
|
Hi there! I've tried to use the mapping in a 4 deck setup. It seems like selecting deck 3 and 4 in the controller setup menu does not work as expected. Edit: found the culprit. In the implementation of the Mixer class, control group names should be created using |
Hi, thanks for the report and the suggested fix. I'm traveling now and will have access to a development system in two weeks again, but than I will miss Reloop Mixtour hardware access for a while. I will check your suggestions and come back. Again, thanks a lot for your suggested patches, regards, Rene |
group indications should reflect the currentDeck, not the midi channel. Thanks for @andrasore for the fix. Co-authored-by: András Sőre <andras08@gmail.com>
group indications should reflect the currentDeck, not the midi channel. Thanks for @andrasore for the pointing to the issue.
andrasore
left a comment
There was a problem hiding this comment.
Hi @absorb-it ! Sorry for the late reply. I've done a quick testing of the mapping fixes. I've noticed two things at a glance:
- When pressing the right "c" button on the controller (for putting the right side control buttons into cue mode), the second button (labeled "sync") does not create a cue. An error dialog is shown
- I think the FX buttons' main functionality should be switching between filter mode and selected quick FX for the channel. This is consistent with the buttons' labels, and is encouraged as per the contributing guidelines. Maybe shift + fx could select the next FX in the quick effects selector list.
fixed boken button, thanks to andrasore for finding he bug!
|
Hi @andrasore , thanks for testing the implementation and filing the bugs...
found this issue and fixed it with def62f7
I get your point, but there is no chance for me to change this now without the real hardware in front of me. Therefore this has to wait until May / June. Thanks and regards, Rene |
|
Hey @absorb-it ! I had some spare time on my hands and managed to change the FX buttons functionality to switch between Filter / Quick FX. Also Shift + FX button should now select the next quick effect in the list. I couldnt push to your repo though so I attached the files here. Edit: I forgot I could have just started a PR there 😅 |
|
Hi @andrasore , thanks for providing the patch, just had a look into it. The midi.xml is ok, no issues. The *js seemed a little bit to complicated, there are some predefined functions in midi-components-0.0.js which really help a lot simplifying the code. But while trying to clean it a little bit I realized some bigger issue with it. Looks like you assumed that the 'Filter' is always at id '11', but this depends on the configuration in your preferences. It's just another FX and can be put at every position, as well as the name can be changed or some Echo can be added. I assumed this should be at position '1', which makes everything easier and that's how it was on my software setup. At the end, this should be mentioned in the documentation. Beside, you missed implementing the option to enable and disable the FX directly in the software interface, this should be mapped back to the state of the Indicator (I missed this as well for the small blue LED, should be fixed now). I changed a lot, but your help is really appreciated - I would not have been able to dig into this without some example code showing me some direction. I have no chance to test the code as of now, therefore also as some attachment, it would be great if you can check if this works at all. All the best, Rene (edit, added fixed file) |
|
I've tested the changes in the included js file. Everything is working correctly, and the code looks nicer too! LGTM |
Filter/FX button now changes between the Quickfilter number 1 (best set this to a plain Filter) and other FX - as labeled on the device. Thanks to @andrasore for code and testing.
|
Hi @andrasore ,
committed with e08506d. I like to mention your work in the midi header author line, if this is ok for you. (as of now: Rene (mixxx at absorb.it), zfhrp). Can I add your name and email? Regards, Rene |
|
Okay, sure!
… *absorb-it* left a comment (mixxxdj/mixxx#15790)
<#15790 (comment)>
Hi @andrasore <https://github.com/andrasore> ,
I've tested the changes in the included js file. Everything is working
correctly, and the code looks nicer too! LGTM
committed with e08506d
<e08506d>
.
I like to mention your work in the midi header author line, if this is ok
for you. (as of now: Rene (mixxx at absorb.it), zfhrp). Can I add your
name and email?
Regards, Rene
—
Reply to this email directly, view it on GitHub
<#15790 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AD2DZGE7FTRFBXEZ5S5VS3D4QRVPDAVCNFSM6AAAAACQCT5JQSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DANJXHAYTENZXHE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
added with 027c777 , feel free to change this the way you like it with a PR. All the best, Rene |
There was a problem hiding this comment.
Pull request overview
Adds an initial Mixxx controller mapping for the Reloop Mixtour, including a JavaScript controller script and an accompanying MIDI XML preset with configurable deck assignment (2-deck usage with optional 4-deck following/highlight behavior).
Changes:
- Introduces
ReloopMixtourcontroller script implementing deck + mixer controls, shift layers, library navigation, and LEDs/meters. - Adds a
.midi.xmlpreset defining the device, script loading, and control bindings plus user settings for left/right deck assignment.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| res/controllers/Reloop-Mixtour-scripts.js | Implements Mixtour behavior using midi-components, including deck/mixer abstractions and LED/meter output. |
| res/controllers/Reloop Mixtour.midi.xml | Defines the Mixxx controller preset, loads the script, and maps MIDI messages + exposes deck-selection settings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| this.masterMeter = new components.Component({ | ||
| midi: [0x90 + midiChannel, 0x12], | ||
| key: (this.currentDeck === "[Channel1]")?"vu_meter_left":"vu_meter_right", |
There was a problem hiding this comment.
masterMeter chooses between vu_meter_left/vu_meter_right based on this.currentDeck. When the mixer follows deck selection (e.g. switching between Channel1 and Channel3), this will flip which master meter is shown and can result in both sides showing the same channel. Tie the selection to the physical side (e.g. midiChannel === 0 => left, midiChannel === 1 => right) rather than the selected deck.
| key: (this.currentDeck === "[Channel1]")?"vu_meter_left":"vu_meter_right", | |
| key: (midiChannel === 0) ? "vu_meter_left" : "vu_meter_right", |
| outValueScale(value) { | ||
| return (engine.getValue(this.group, this.secondOutKey) && (Math.abs(0.5 - value) > 0.01))?0x7F:0x00; |
There was a problem hiding this comment.
fxIndicator connects to both super1 and enabled, but outValueScale(value) treats its argument as the super1 value. When the enabled connection triggers, value will be 0/1 (enabled state), causing the center-detent check to be wrong and the LED to light even if super1 is centered. Make outValueScale independent of the callback argument by reading the current super1 value from Mixxx (or override output() to fetch both super1 and enabled).
| outValueScale(value) { | |
| return (engine.getValue(this.group, this.secondOutKey) && (Math.abs(0.5 - value) > 0.01))?0x7F:0x00; | |
| outValueScale() { | |
| var super1Value = engine.getValue(this.group, this.outKey); | |
| var enabledValue = engine.getValue(this.group, this.secondOutKey); | |
| return (enabledValue && (Math.abs(0.5 - super1Value) > 0.01)) ? 0x7F : 0x00; |
| // override Component prototype to prevent double connections | ||
| // original connect function will override connections[0] and | ||
| // this way looses control of existing connection | ||
| components.Component.prototype.connect = function() { | ||
| if (this.connections[0] === undefined && // <-- added this condition | ||
| undefined !== this.group && | ||
| undefined !== this.outKey && | ||
| undefined !== this.output && | ||
| typeof this.output === "function") { | ||
| this.connections[0] = engine.makeConnection(this.group, this.outKey, this.output.bind(this)); | ||
| } | ||
| }; | ||
| // override Component prototype to reset connection after disconnect | ||
| // original disconnect will never reset connections[0] to undefined | ||
| components.Component.prototype.disconnect = function() { | ||
| if (this.connections[0] !== undefined) { | ||
| this.connections.forEach(function(conn) { | ||
| conn.disconnect(); | ||
| }); | ||
| } | ||
| this.connections = []; // <-- added this | ||
| }; |
There was a problem hiding this comment.
This script globally overrides components.Component.prototype.connect/disconnect. Because controller scripts share the same JS runtime, this monkey-patch can affect other mappings that use midi-components-0.0.js when multiple controllers are enabled, and it makes behavior depend on load order. Consider avoiding prototype overrides (e.g. fix usage sites by ensuring disconnect() clears connections before reconnecting, or wrap/patch in a guarded, idempotent way and restore originals on shutdown).
| this.connectFourDeckControl = function() { | ||
| for (let i = 1; i <= 4; i++) { | ||
| engine.makeConnection("[Skin]", `highlight_deck_[Channel${i}]`, function(_value, _group, _control) { | ||
| ReloopMixtour.reSelectDecks(); | ||
| }); | ||
| engine.makeConnection("[Skin]", `highlight_mixer_[Channel${i}]`, function(_value, _group, _control) { | ||
| ReloopMixtour.reSelectMixer(); | ||
| }); | ||
| } | ||
| }; |
There was a problem hiding this comment.
connectFourDeckControl() creates 8 engine.makeConnection(...) objects but does not keep references to them, so they cannot be disconnected in shutdown(). If the mapping is reloaded or the controller is unplugged/replugged, this can leave stale connections and cause callbacks to fire multiple times. Store the returned connection objects (e.g. on ReloopMixtour) and disconnect them in shutdown().
| <group>[Library]</group> | ||
| <key>ReloopMixtour.backBtn.input</key> | ||
| <description>Shift [BACK]</description> | ||
| <status>0x90</status> | ||
| <midino>0x47</midino> | ||
| <options> | ||
| <normal/> | ||
| </options> | ||
| </control> | ||
| <control> |
There was a problem hiding this comment.
This <control> duplicates the Shift [BACK] mapping for the same MIDI message (status 0x90, midino 0x47) but uses <normal/> while the <key> points to a script function (ReloopMixtour.backBtn.input). This will either be ignored or conflict with the earlier script-binding definition and can make Shift+BACK unreliable. Remove the duplicate entry or change it to a single <script-binding/> mapping.
| <group>[Library]</group> | |
| <key>ReloopMixtour.backBtn.input</key> | |
| <description>Shift [BACK]</description> | |
| <status>0x90</status> | |
| <midino>0x47</midino> | |
| <options> | |
| <normal/> | |
| </options> | |
| </control> | |
| <control> |
| group: `[QuickEffectRack1_${theMixer.currentDeck}]`, | ||
| // set preset to first real fx. if available at all this is number 2 | ||
| fxPreset: (engine.getValue(this.group, "num_chain_presets") > 2)?2:0, | ||
| nextPreset: function() { |
There was a problem hiding this comment.
fxPreset is initialized using engine.getValue(this.group, ...), but at this point this refers to the surrounding ReloopMixtour.Mixer instance (which has no group), not the components.Button being constructed. This will read from an undefined group (or throw) and can break FX selection. Compute the QuickEffectRack group in a local variable (or use theMixer.currentDeck) and use that in the engine.getValue(...) call instead of this.group during initialization.
| } | ||
|
|
||
| setCurrentDeck(newGroup) { | ||
| this.effect.reconnect(newGroup); |
There was a problem hiding this comment.
setCurrentDeck() calls this.effect.reconnect(newGroup), but components.Button/components.Component does not define a reconnect method (only ComponentContainer.reconnectComponents). This will throw at runtime when changing decks. Remove this call or implement reconnection by calling disconnect()/updating group/connect() (or rely on super.setCurrentDeck() to handle group updates).
| this.effect.reconnect(newGroup); |
|
Hi, I won't fix any hallucinated issues brought in by KI. Nor will I improve the quality of this KI with my comments on it's suggestions. If anybody else likes to take the time and go to this, feel free. Rene |
This is a implementation for the midi-controller Reloop Mixtour. It is a two deck controller and you configure the Decks for which to use this controller, if you have two of them you can control 4 decks with it.
Related documentation is at mixxxdj/manual#825