SOLVED - Need help activating subpages with button

Dear forum members,
whenever I try to activate a subpage by the press of a button I have to push it twice before the change takes place. I have tried different setups for that button like push / toggle / momentary and tap (editable in my controller) but I cannot make the change happen instantly with the first button press.
Any help is appreciated,
Emre

function makePageSelectedTrack() {
  var page = makePageWithDefaults("SelectedTrack");

  var console1SubPageArea = page.makeSubPageArea("Console1");
  var console1EqSubPage = console1SubPageArea.makeSubPage("C1_Eq");
  var console1DynSubPage = console1SubPageArea.makeSubPage("C1_Dyn");

  page.makeActionBinding(
    surfaceElements.touchButtonsL[0].mSurfaceValue,
    console1EqSubPage.mAction.mActivate
  );
  page.makeActionBinding(
    surfaceElements.touchButtonsL[1].mSurfaceValue,
    console1DynSubPage.mAction.mActivate
  );

  numAssignableEncoders = 12;
  var numParameters = numAssignableEncoders * 4;
  var parameters = [];

  var selectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel;

  // Accessing object to Insert of selected track
  var HostInsertViewer = selectedTrackChannel.mInsertAndStripEffects
    .makeInsertEffectViewer("")
    .excludeEmptySlots()
    .followPluginWindowInFocus();

  // Create Paramaters Array
  for (var i = 0; i < numParameters; i++) {
    var parameter = HostInsertViewer.mParameterBankZone.makeParameterValue();
    parameters.push(parameter);
  }
console1EqSubPage.mAction.mActivate;

  console1EqSubPage.mOnActivate = function () {
    // Bind knobs and buttons of encoders array to parameters
    for (var i = 0; i < numAssignableEncoders; i++) {
      page.makeValueBinding(
        surfaceElements.encoders[i].mEncoderValue,
        parameters[i]
      );
      page
        .makeValueBinding(
          surfaceElements.encoders[i].mPushValue,
          parameters[i + numAssignableEncoders]
        )
        .setTypeToggle();
      printEncoderDisplay(i);
    }
  };

  console1DynSubPage.mOnActivate = function () {
    for (var idx = 0; idx < numAssignableEncoders; ++idx) {
      page.makeValueBinding(
        surfaceElements.encoders[idx].mEncoderValue,
        parameters[idx + numAssignableEncoders * 2]
      );
      page
        .makeValueBinding(
          surfaceElements.encoders[idx].mPushValue,
          parameters[idx + numAssignableEncoders * 3]
        )
        .setTypeToggle();
      printEncoderDisplay(idx);
    }
  };

  return page;
}

This part of the code looks correct.
What you describe is most probably due to the touchButtonsL[0-1] being set to toggle mode.
You can inspect that for a start, by placing in your code this function:

surfaceElements.touchButtonsL[0].mSurfaceValue.mOnProcessValueChange=function(activeDevice,value,diff){
    console.log("touchB0 value set to "+value+" diff="+diff)
}

Open your remote console, and press 2-3 times the touchButtonL[0] in order to trigger this function, and from there by posting a screenshot, we can work this out I hope.

Thanks for your ultrafast reply.
I tried your suggestion but somehow I don´t get any logs:

function makePageSelectedTrack() {
  var page = makePageWithDefaults("SelectedTrack");
console.log('Page Selected Track created');

  var console1SubPageArea = page.makeSubPageArea("Console1");
  var console1EqSubPage = console1SubPageArea.makeSubPage("C1_Eq");
  var console1DynSubPage = console1SubPageArea.makeSubPage("C1_Dyn");

  page.makeActionBinding(
    surfaceElements.touchButtonsL[0].mSurfaceValue,
    console1EqSubPage.mAction.mActivate
  );
  page.makeActionBinding(
    surfaceElements.touchButtonsL[1].mSurfaceValue,
    console1DynSubPage.mAction.mActivate
  );

  surfaceElements.touchButtonsL[0].mSurfaceValue.mOnProcessValueChange=function(activeDevice,value,diff){
    console.log("touchB0 value set to "+value+" diff="+diff)
}

  numAssignableEncoders = 12;
  var numParameters = numAssignableEncoders * 4;
  var parameters = [];

  var selectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel;

  // Accessing object to Insert of selected track
  var HostInsertViewer = selectedTrackChannel.mInsertAndStripEffects
    .makeInsertEffectViewer("")
    .excludeEmptySlots()
    .followPluginWindowInFocus();

  // Create Paramaters Array
  for (var i = 0; i < numParameters; i++) {
    var parameter = HostInsertViewer.mParameterBankZone.makeParameterValue();
    parameters.push(parameter);
  }

  console1EqSubPage.mOnActivate = function () {
    // Bind knobs and buttons of encoders array to parameters
    for (var i = 0; i < numAssignableEncoders; i++) {
      page.makeValueBinding(
        surfaceElements.encoders[i].mEncoderValue,
        parameters[i]
      );
      page
        .makeValueBinding(
          surfaceElements.encoders[i].mPushValue,
          parameters[i + numAssignableEncoders]
        )
        .setTypeToggle();
      printEncoderDisplay(i);
    }
  };

  console1DynSubPage.mOnActivate = function () {
    for (var idx = 0; idx < numAssignableEncoders; ++idx) {
      page.makeValueBinding(
        surfaceElements.encoders[idx].mEncoderValue,
        parameters[idx + numAssignableEncoders * 2]
      );
      page
        .makeValueBinding(
          surfaceElements.encoders[idx].mPushValue,
          parameters[idx + numAssignableEncoders * 3]
        )
        .setTypeToggle();
      printEncoderDisplay(idx);
    }
  };

  return page;
}```

Sorry, I forgot to mention that in order to get the logs, you should first comment out the valueBinding line:

//page.makeActionBinding(surfaceElements.touchButtonsL[0].mSurfaceValue,console1EqSubPage.mAction.mActivate);

Thanks, this is what I got:

This is my controller buttons setup:


And this is my controllers log:

So it is basically sending a note on/off…

Just to be clear, when you press ONCE the button, you receive both value 1 and then 0? This is how I read in the logs (for example at time 02:10:15).

I guess so, just tried again:

OK, so the buttons are in gate mode. Then, you shouldn’t have any problem at all.

BUT now I see the real problem, it’s actually how you setup the subpages. You think that the assignments should be made inside the mOnActivate events, while this is not unfortunately true, though I can understand why you thought this way.

Let me quickly rewrite it for you:

function makePageSelectedTrack() {

    var page = makePageWithDefaults("SelectedTrack");
  
    var console1SubPageArea = page.makeSubPageArea("Console1");
    var console1EqSubPage = console1SubPageArea.makeSubPage("C1_Eq");
    var console1DynSubPage = console1SubPageArea.makeSubPage("C1_Dyn");
  
    page.makeActionBinding(surfaceElements.touchButtonsL[0].mSurfaceValue,console1EqSubPage.mAction.mActivate);
    page.makeActionBinding(surfaceElements.touchButtonsL[1].mSurfaceValue,console1DynSubPage.mAction.mActivate);
  
    var selectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel;
  
    // Accessing object to Insert of selected track
    var HostInsertViewer = selectedTrackChannel.mInsertAndStripEffects
      .makeInsertEffectViewer("")
      .excludeEmptySlots()
      .followPluginWindowInFocus();
  
    // Create Paramaters Array
    numAssignableEncoders = 12;
  
    var numParameters = numAssignableEncoders * 4;
  
    var parameters = [];
  
    for (var i = 0; i < numParameters; i++) {
      var parameter = HostInsertViewer.mParameterBankZone.makeParameterValue();
      parameters.push(parameter);
    }
  
  //  console1EqSubPage.mAction.mActivate;
  
    for (var i = 0; i < numAssignableEncoders; i++) {
    
        page.makeValueBinding(
        surfaceElements.encoders[i].mEncoderValue,
        parameters[i]
        ).setSubPage(console1EqSubPage);
        
        page
        .makeValueBinding(surfaceElements.encoders[i].mPushValue,parameters[i+numAssignableEncoders])
        .setTypeToggle().setSubPage(console1EqSubPage);
        
        printEncoderDisplay(i);
    
    }

    for (var idx = 0; idx < numAssignableEncoders; ++idx) {
    
        page.makeValueBinding(surfaceElements.encoders[idx].mEncoderValue,parameters[idx+numAssignableEncoders*2]).setSubPage(console1DynSubPage);
        
        page.makeValueBinding(surfaceElements.encoders[idx].mPushValue,parameters[idx+numAssignableEncoders*3]
        ).setTypeToggle().setSubPage(console1DynSubPage);
    
        printEncoderDisplay(idx);
    
    }

    console1EqSubPage.mOnActivate = function () {
      
      
    };
  
    console1DynSubPage.mOnActivate = function () {
      
    };
  
    return page;
  
}

Please inspect the code in order to understand how the subPages concept really works.

By the way, what exactly is the sub printEncoderDisplay supposed to do?

1 Like

Thanks a lot Minas, I am as always impressed by your knowledge and huge helpfulness!
You are right, I didn´t get the concept of subpages yet and I haven´t found a clear documentation in that regard. I wonder how others like you get into these concepts…
Anyway, your code works perfect and I am very happy!
My function printEncoderDisplay() is responsible for pushing the data to my mobile phones display. I use another software calles open stage control to make my phone act like a controller, all midi is merged with bome midi translator. If you want to know more details let me know…

// Print encoder display
function printEncoderDisplay(idx) {
  var rows = [0x14, 0x15, 0x16];
  rows.forEach(function(row) {
    var valueType, trigger;
    if (row == 0x14) {
      valueType = 'mEncoderValue';
      trigger = 'mOnTitleChange';
    } else if (row == 0x15) {
      valueType = 'mEncoderValue';
      trigger = 'mOnDisplayValueChange';
    } else if (row == 0x16) {
      valueType = 'mPushValue';
      trigger = 'mOnDisplayValueChange';
    }
    surfaceElements.encoders[idx][valueType][trigger] =
      function (activeDevice, arg1, arg2) {
        var print = row == 0x14 ? arg2 : arg1;
        var startAt = 0x00;
        var OscLcdIdx = 11 + this.idx;
        var numColumns = 10;
        var OscLcdIdxSysex = "0x" + OscLcdIdx.toString();
        var dataDisplay = [0xf0, 0x00, 0x00, 0x66, row, OscLcdIdxSysex, startAt];
        var printLength = print.length;

        if (printLength < numColumns) {
          while (printLength++ < numColumns) {
            print = print + " ";
          }
        }

        for (var i = 0; i < numColumns; ++i) {
          dataDisplay.push(print.charCodeAt(i));
        }

        dataDisplay.push(0xf7);
        midiOutput.sendMidi(activeDevice, dataDisplay);
      }.bind({ idx });
  });
}

I wish you and everybody else a merry Christmas and a wonderful time with your beloved ones!
Emre

1 Like

After altering the code, you can keep this function just in the first for loop, since the contents as far as I can tell are identical, so in reality the second one is just a duplicate.

Season’s Greetings!

Very good hint, will make the code cleaner, thanks again!