Allen&Heath Xone K2 switch filter/loops on top encoder

Hello,

after a while I managed to get my Xone K2 working on my own mapping, based on the example but changing some things.

I would like to use the top encoder for two different functions:

Roll encoder:
- filter or double/halve loopsize
Press:
- activate/end loop at the current position

I would like to switch between them by pressing another button once (this is, not keeping it pressed).

So it would be something like this:

this.encoder = new components.Encoder({

if (buttonWasPressed == True)
{ top encoder used as a filter }
else
{ double/halve loopsize}
}

this.encoderPress = new components.Button({

{ activate/end loop at current position }
}

My code would look something like this:


this.encoder = new components.Encoder({
        
if (ButtonWasPressed == True) {
            unshift: function () {
            this.input = function (channel, control, value, status, group) {
                if (value === 0x01) {
                    engine.setValue(this.group, 'loop_double', 1);
                 } 
                else {
                    engine.setValue(this.group, 'loop_halve', 1);
                 }
            }
     }
else {

     filter use
}

            
 this.encoderPress = new components.Button({
       
if (ButtonWasPressed == True) {
            unshift: function () {
          
               activate/end loop at current position
           
        },  

I am having difficulties in these two parts:

  1. Implementing the switch button: what is the best way to do it? Is there an existing function which does this, such as “IsPressed”?
    Or would it be better to toggle the value of some kind of global variable when the button is pressed?

  2. Start/end loop at current position: the “beatloop” and “reloop” controls seem to keep record of the position the loop was set first and jump to that specific position, what I need is to start or end the loop anywhere.

Attached are my scripts.js and xml files

I would be very grateful for any help!

Uri
Allen-and-Heath-Xone-K2-scripts.js (36.5 KB)

Hi everybody,

so, after a while I kept working on this mapping, and would like some feedback to know if my approach is conceptually right or there is something I should be doing otherwise.

In the configuration I have in mind, the top encoder would have two functions:

  • Normal mode (not switched):
    Roll encoder:
    - filter or double/halve loopsize
    Press:
    - activate/end loop at the current position

  • Filter mode (switched by pressing topButtons[1] once)

    • Encoder used as quick filter knob

So topButtons[1] would jump to filterMode() when pressed, like this:

this.topButtons = new components.ComponentContainer();
    this.topButtons[1] = new components.Button({
       unshift: function () {
        this.group = '[QuickEffectRack1_' + this.deckString + '_Effect1]'; //select quick filter knob group
        this.inKey: 'enabled'; //enable quick filter knob
        this.input = function (channel, control, value, status) {
            deckColumn.encoder.filterMode(); //top encoder used as filter knob
        };
        this.color = XoneK2.color.amber;
        },
});

And in the encoder definition I set up both the loop behaviour previously defined and the filter:

this.encoder = new components.Encoder({
        unshift: function () {
            this.input = function (channel, control, value, status, group) {
                if (value === 0x01) {
                    engine.setValue(this.group, 'loop_double', 1); //double loop length
                } 
                else {
                    engine.setValue(this.group, 'loop_halve', 1);  //halve loop length
                }
            };
            },
        shift: function () {
            something else...
        },
        supershift: function () {
            some other code...               
        },
        filterMode: function () {
             this.group = '[QuickEffectRack1_' + this.deckString + ']'; //select quick filter knob group
             this.inKey: 'super1'; //filter depth knob
             this.input = function (channel, control, value, status) {
                 var depth = engine.getValue("[QuickEffectRack1_" + this.deckString + "]", "super1");
 
                 if (value === 1) {
                     depth += 0.1;
                 } else {
                     depth -= 0.1;
                 }
             engine.setValue("[QuickEffectRack1_' + this.deckString + ']", "super1", depth);
             };
         },
    });

    this.encoderPress = new components.Button({
        outKey: 'loop_enabled',
        unshift: function () {
            this.input = function (channel, control, value, status, group) {
                 if (this.inGetValue() === 0x01) {
                       if (engine.getValue(this.group,'loop_enabled') === 1) {  //check if a loop is enabled    
                                engine.setValue(this.group, 'reloop_toggle', 1);  //if true, disable the loop
                 } 
                else {
                                engine.setValue(this.group, 'beatloop_activate', 1);  //if false, enable a loop
               }
             };
        },
        shift: function () {
           ...
        },
        supershift: function () {
           ...
        },
    });

In the mapping provided with Mixxx this activate/end loop feature is implemented using two buttons, so there might be some reason for this I am quite not getting, or is it possible to get it done with one button/encoder?

Thanks a lot in advance!!

Uri

Hello,

does somebody have an answer or tip to help me out on this specific topic?

Thanks a lot! :slight_smile:

If you don’t get an answer here, you can always ask mapping development questions by creating a new topic in the “controller mappings” stream on Zulip: https://mixxx.zulipchat.com/#narrow/stream/113295-controller-mapping

I don’t recommend using coarse stepped encoder for a filter knob. Either the knob has to turn with big steps to match the angular change of the encoder, which doesn’t sound good, or you need to make each step of the encoder move the knob a small step to smooth it out, which requires turning the encoder a bunch.

In the mapping now in 2.3 beta, the QuickEffect superknob is available with shift + low EQ knob.

Only because the encoder is used for other features. If there was another encoder available per deck, I’d prefer to use that for looping too, but this is a small controller.

So if I free the encoder from other functionalities, could this toggle function and the loop in/loop out feature still be done somehow?

even if using a stepped encoder is not the best option I would like to give it a try.

What should I be changing on my previous example?

Thank you very much

Sure, you can map it to whatever you want. It’s just up to you to write the script. If you try using the encoder to control the filter, I think you will experience what I wrote above. A controller I used before the Xone K2 (Hercules P32) had an encoder labeled as “Filter” so I tried mapping it that way. I didn’t think it was worth using that for a filter, so I ended up remapping that to something else.

Hi

I checked the 2.3 script and I think it makes more sense to leave the filter on the eq knob, just as you implemented it.

I am still struggling with the loop in/loop out functionality on top encoder press, could you give me a hint?

It should be something like this, I still don’t get if I am using the right controls…

this.encoderPress = new components.Button({
        outKey: 'loop_enabled',
        unshift: function () {
            this.input = function (channel, control, value, status, group) {
                 if (this.inGetValue() === 0x01) {
                       if (engine.getValue(this.group,'loop_enabled') === 1) {  //check if a loop is enabled    
                                engine.setValue(this.group, 'reloop_toggle', 1);  //if true, disable the loop
                 } 
                else {
                                engine.setValue(this.group, 'beatloop_activate', 1);  //if false, enable a loop
               }
             };
        },

Thanks a lot!

Uri

Use script.triggerControl instead of engine.setValue to reset the button Controls to 0. Otherwise that looks like it should work.