I’m having an issue with my MIDI Remote script for a rotary encoder. This encoder sends relative CC values and I use a custom value variable that I map to the host function.
I’m experiencing “jitter” or unstable values when I try to capture the value from the callback function mOnValueChange
. To illustrate, this is what recorded automation looks like:
If I do not capture the updated values in mOnValueChange
I get a none of this jitter.
I suspect I am doing something backwards in my script, but can’t figure out what and I’m hoping someone more experienced with the API could shed some light in where I went wrong.
At one point I suspected rounding errors in the floating point value to be the culprit and added Math.round()
in several places. It did not make a difference.
I’m also curious as to why the mOnValueChange
gets called twice every time setProcessValue
is being called. I believe this is only true if the value binding uses the setValueTakeOverModeJump()
method. Other value takeover methods does not seem to work in my case.
If the value is changed from the host, mOnValueChange
only gets called once.
My script for one encoder
(The one line that seems to cause this jitter is toward the end of the script.)
//-----------------------------------------------------------------------------
// 1. DRIVER SETUP - create driver object, midi ports and detection information
//-----------------------------------------------------------------------------
var midiremote_api = require('midiremote_api_v1')
var expectedName = "Midi Fighter Twister Pro"
var deviceDriver = midiremote_api.makeDeviceDriver('DJ TECHTOOLS', expectedName, 'mlindeb')
var midiInput = deviceDriver.mPorts.makeMidiInput()
var midiOutput = deviceDriver.mPorts.makeMidiOutput()
deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
.expectInputNameEquals('Midi Fighter Twister')
.expectOutputNameEquals('Midi Fighter Twister')
var surface = deviceDriver.mSurface
//----------------------------------------------------------------------------------------------------------------------
// 2. SURFACE LAYOUT - create control elements and midi bindings
//----------------------------------------------------------------------------------------------------------------------
function makeEncoder(x, y, CC, channel) {
var knob = {}
knob.res = 0.005
knob.encoder = surface.makeKnob(x, y, 1, 1)
knob.channel = 0xb0 + channel
knob.encoder.mSurfaceValue.mMidiBinding.setInputPort(midiInput).bindToControlChange(channel, CC)
knob.cc = CC
knob.pv = deviceDriver.mSurface.makeCustomValueVariable("Knob" + CC)
knob.realValue = 0
knob.encoder.mSurfaceValue.mOnProcessValueChange = function (device, value, value2) {
var incSign = (value < 0.5) ? -1 : 1
var absValue = Math.abs(value - 0.5)
var incAdj = (absValue>0.02) ? absValue * 100 : 1
var Adj = incSign * incAdj * knob.res
knob.realValue = knob.realValue + Adj
knob.realValue = Math.min(Math.max(knob.realValue, 0.0), 1.0)
knob.pv.setProcessValue(device, knob.realValue)
}
knob.encoder.mSurfaceValue.mOnDisplayValueChange = function(device, val1, val2) {
//This function does not seem to get called ever
console.log('val1: ' + val1 + ', val2: ' + val2)
}
return knob
}
function makeSurfaceElements() {
var surfaceElements = {}
surfaceElements.knob = {}
surfaceElements.knob[0] = makeEncoder(0, 0, 0, 0)
return surfaceElements
}
var SE = makeSurfaceElements()
//----------------------------------------------------------------------------------------------------------------------
// 3. HOST MAPPING - create mapping pages and host bindings
//----------------------------------------------------------------------------------------------------------------------
function makePages() {
var page = deviceDriver.mMapping.makePage("Main")
//BINDINGS **********************
var selCh = page.mHostAccess.mTrackSelection.mMixerChannel
//Knob 0
page.makeValueBinding(SE.knob[0].pv, selCh.mChannelEQ.mBand1.mFreq).setValueTakeOverModeJump()
.mOnValueChange = function (activeDevice, activeMapping, value, diffValue) {
midiOutput.sendMidi(activeDevice, [SE.knob[0].channel, SE.knob[0].cc, Math.round(value * 127)])
var absDiff = Math.abs(diffValue)
//This callback function gets called twice every time the encoder sends a new value
//The second time it gets called the 'value' parameter is of a very small value
if (absDiff > 0.005) {
// Removing this next line removes the jitter
SE.knob[0].realValue = value //<------------- My problem line
}
}
return page
}
var pages = makePages()