Question Midi Remote Script - Pitch Bend / PreSonus FP (2018 Version)

Hello all,

I try to write a script for the PreSonus FaderPort 2018 Version but I’m stuck with the fader:

The FaderPort sends 2 Midi messages for the motorized Fader. Note-On & Note Off for indicating the touch of the fader + Pitch Bend for the position change.

The connection to the volume doesn’t work like expected. Interestingly the volume change is communicated perfectly to the FaderPort but the moving the fader on the FaderPort doesn’t change anything in Cubase.

May someone sees the error immediately…

Thx for helping out

//-----------------------------------------------------------------------------
// 1. DRIVER SETUP - create driver object, midi ports and detection information
//-----------------------------------------------------------------------------

// get the api's entry point
var midiremote_api = require('midiremote_api_v1')

// create the device driver main object
var deviceDriver = midiremote_api.makeDeviceDriver('PreSonus', 'FaderPort', 'xxx')

// create objects representing the hardware's MIDI ports
var midiInput = deviceDriver.mPorts.makeMidiInput()
var midiOutput = deviceDriver.mPorts.makeMidiOutput()

// define all possible namings the devices MIDI ports could have
// NOTE: Windows and MacOS handle port naming differently
//deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
//    .expectInputNameEquals('SimpleDevice IN')
//    .expectOutputNameEquals('SimpleDevice OUT')
    
deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('PreSonus FP2')
    .expectOutputNameEquals('PreSonus FP2')


//-----------------------------------------------------------------------------
// 2. SURFACE LAYOUT - create control elements and midi bindings
//-----------------------------------------------------------------------------

// create control element representing your hardware's surface
var fd_Volume = deviceDriver.mSurface.makeFader(2, 0, 1, 2).setTypeVertical()
var btn_Volume = deviceDriver.mSurface.makeButton(1, 0, 1, 1)

var kb_Rotary = deviceDriver.mSurface.makeKnob(0, 3, 1, 1)

var btn_Solo = deviceDriver.mSurface.makeButton(0, 0, 1, 1)

var btn_PrevTrack = deviceDriver.mSurface.makeButton(0, 1, 1, 1)
var btn_NextTrack = deviceDriver.mSurface.makeButton(1, 1, 1, 1)

// bind midi ports to surface elements

fd_Volume.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToPitchBend(0)

btn_Volume.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 104)

kb_Rotary.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 176)

btn_Solo.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 8)

btn_PrevTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 46)

btn_NextTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 47)


//-----------------------------------------------------------------------------
// 3. HOST MAPPING - create mapping pages and host bindings
//-----------------------------------------------------------------------------

// create at least one mapping page
var page = deviceDriver.mMapping.makePage('Example Mixer Page')

// bind surface elements to host accessing object values

page.makeActionBinding(btn_PrevTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mPrevTrack)
page.makeActionBinding(btn_NextTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mNextTrack)


// create host accessing objects
var hostSelectedMixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel

page.makeValueBinding(fd_Volume.mSurfaceValue, hostSelectedMixerChannel.mValue.mVolume)

fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, newValue, oldValue) {
    console.log("PV: " + fd_Volume.mSurfaceValue.getProcessValue(context).toString())
    console.log("NV: " + newValue.toString())
}

Hi,

To me, it looks OK. Sorry…

For me too :frowning:

The log out shows values between 0 and 1 as floating point value. May this is the issue…

Hi @WEM,
sorry, the “oldvalue” thing is outdated. Did I miss to remove it from the example scripts? I’ll have a look. There should only be “newValue” or just “value” als second parameter for “mOnProcessValueChange”.

No, that indicates it is working correctly.

Does the FaderPort have more than one input port? If the output side looks alright, then I’m suspecting the solution is found on the input side.

1 Like

I’ll have a look on the “oldvalue” thing.

There is only one midi port on the FaderPort.

What’s kind of strange to me: “Cubase → FaderPort” works but the other way not (Moving Chanel volume by mouse moves the fader on the FaderPort)

The next/prev track buttons and functions are working perfectly. So in general the midi in is working.

Werner

@WEM did you try to disable the script and enable the “good old” Mackie Control integration in the Studio Setup? Would surprise me if the input works there but not on the new MIDI Remote system.

Yes, Mackie Control works flawless (when the FaderPort is switched into MCU / Cubase mode, disable the script, …).

The FaderPort has different modes: MCU (for Cubase), HUI and a “FaderPort Multichannel Controller MIDI Protocol”. I used the FaderPort Multichannel Controller MIDI Protocol mode to build the script (Manual 43ff).

FaderPort Manual

MidiOx shows exactly the messages described in the manual.

Hi @WEM, are you sure the Mapping Assistant window is CLOSED? It must be closed, otherwise MIDI messages will be “consumed” by the Mapping Assistant’s “learn” mode.

Yes. The learning assistent was/is closed.
The next/prev buttons are working correctly - so the general midi setup & communication from the FaderPort to Cubase and backwards looks ok to me.
If the mapping assstent would be open, than also the next/prev buttons would not work…

In my opinion the issue must be connected to the fader & pitchbend: the FaderPort sends a Midi Note On message, then while moving the fader the pitch bend messages itself. At the end of the movement comes a Note Off message. Do I have to connect the Note On/Off message somehow?

The Note On/Off shouldn’t have anything todo with it. I’m running out of ideas already. Will think again later, sorry for the trouble…

No need to apologize. :slight_smile:

Same here, tried it over a few hours yesterday without success and felt stuck…

Tried it first with the GUI tool and GUI mapping assistent. Same behaviour. I changed to script in order to have more debugging / controlling possibilities.

I have still no success with the motorfader of my FaderPort 2018 :frowning:

Tried a few things now:

  • Next/Prev buttons are working like expected
  • The direction Cubase to FaderPort works fine
  • The direction FaderPort to Cubase mostly doens’t work (cubase accepts when I move the fader to min position and sometimes - not really reproducible - also between)

My opinion is that it’s a bug/issue with the PitchBend handling… may someone has a clue what happens here.

Here the midi trace (MIDIOX):

 00003EB3  21  --     90    68    7F    1  G# 7 Note On               
 00003EBD  21  --     E0    15    2C    1  ---  Pitch Bend            
 00003EF9  21  --     E0    48    2C    1  ---  Pitch Bend            
 00003F0D  21  --     E0    1D    2D    1  ---  Pitch Bend            
 00003F21  21  --     E0    36    2E    1  ---  Pitch Bend            
 00003F35  21  --     E0    4E    2F    1  ---  Pitch Bend            
 00003F49  21  --     E0    78    30    1  ---  Pitch Bend            
 00003F5D  21  --     E0    21    32    1  ---  Pitch Bend            
 00003F71  21  --     E0    49    33    1  ---  Pitch Bend            
 00003F85  21  --     E0    4C    34    1  ---  Pitch Bend            
 00003F99  21  --     E0    70    35    1  ---  Pitch Bend            
 00003FAD  21  --     E0    42    36    1  ---  Pitch Bend            
 00003FC1  21  --     E0    03    37    1  ---  Pitch Bend            
 00003FD5  21  --     E0    24    37    1  ---  Pitch Bend            
 00004039  21  --     E0    42    36    1  ---  Pitch Bend            
 0000404D  21  --     E0    70    35    1  ---  Pitch Bend            
 00004061  21  --     E0    7D    34    1  ---  Pitch Bend            
 00004075  21  --     E0    7A    33    1  ---  Pitch Bend            
 00004089  21  --     E0    76    32    1  ---  Pitch Bend            
 0000409D  21  --     E0    6E    31    1  ---  Pitch Bend            
 000040B1  21  --     E0    45    30    1  ---  Pitch Bend            
 000040C5  21  --     E0    3D    2F    1  ---  Pitch Bend            
 000040D9  21  --     E0    46    2E    1  ---  Pitch Bend            
 000040ED  21  --     E0    3F    2D    1  ---  Pitch Bend            
 00004101  21  --     E0    6A    2C    1  ---  Pitch Bend            
 00004115  21  --     E0    04    2C    1  ---  Pitch Bend            
 00004129  21  --     E0    0E    2B    1  ---  Pitch Bend            
 0000413D  21  --     E0    17    2A    1  ---  Pitch Bend            
 00004151  21  --     E0    42    29    1  ---  Pitch Bend            
 00004165  21  --     E0    10    29    1  ---  Pitch Bend            
 00004179  21  --     E0    6E    28    1  ---  Pitch Bend            
 000041A1  21  --     E0    3B    28    1  ---  Pitch Bend            
 000041D3  21  --     E0    3B    28    1  ---  Pitch Bend            
 000041D3  21  --     90    68    00    1  G# 7 Note Off

Here the log messages from Cubases:

And the scprit itself:

//-----------------------------------------------------------------------------
// 1. DRIVER SETUP - create driver object, midi ports and detection information
//-----------------------------------------------------------------------------

// get the api's entry point
var midiremote_api = require('midiremote_api_v1')

// create the device driver main object
var deviceDriver = midiremote_api.makeDeviceDriver('PreSonus', 'FaderPort', 'WEM')

// create objects representing the hardware's MIDI ports
var midiInput = deviceDriver.mPorts.makeMidiInput()
var midiOutput = deviceDriver.mPorts.makeMidiOutput()

// define all possible namings the devices MIDI ports could have
// NOTE: Windows and MacOS handle port naming differently

deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('SimpleDevice IN')
    .expectOutputNameEquals('SimpleDevice OUT')

deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('PreSonus FP2')
    .expectOutputNameEquals('PreSonus FP2')

//-----------------------------------------------------------------------------
// 2. SURFACE LAYOUT - create control elements and midi bindings
//-----------------------------------------------------------------------------

// create control element representing your hardware's surface

var fd_Volume = deviceDriver.mSurface.makeFader(2, 0, 1, 2)
    .setTypeVertical()

var btn_Volume = deviceDriver.mSurface.makeButton(1, 0, 1, 1)
var kb_Rotary = deviceDriver.mSurface.makeKnob(0, 3, 1, 1)
var btn_Solo = deviceDriver.mSurface.makeButton(0, 0, 1, 1)
var btn_PrevTrack = deviceDriver.mSurface.makeButton(0, 1, 1, 1)
var btn_NextTrack = deviceDriver.mSurface.makeButton(1, 1, 1, 1)

// bind midi ports to surface elements

fd_Volume.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToPitchBend(0)

btn_Volume.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 104)

kb_Rotary.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 176)

btn_Solo.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 8)

btn_PrevTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 46)

btn_NextTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 47)

//-----------------------------------------------------------------------------
// 3. HOST MAPPING - create mapping pages and host bindings
//-----------------------------------------------------------------------------

// create at least one mapping page
var page = deviceDriver.mMapping.makePage('Example Mixer Page')

// create host accessing objects
var hostSelectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel

// bind surface elements to host accessing object values
page.makeActionBinding(btn_PrevTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mPrevTrack)

page.makeActionBinding(btn_NextTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mNextTrack)

// create host accessing objects
var hostSelectedMixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel

page.makeValueBinding(fd_Volume.mSurfaceValue, hostSelectedMixerChannel.mValue.mVolume)
    .setValueTakeOverModeJump()

fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) {
    console.log("mOnProcessValueChange: " + value.toString())
}

btn_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) {
    if (value == 1) {
        console.log("Fader Action On")
    } else {
        console.log("Fader Action Off")        
    }
}

please remove those lines. Doesn’t address your problem but makes the code cleaner.

Hi @WEM,

Is btn_Volume representing the touch sensor on the fader cap?

I’ve fast-hacked this wihtout testing, please adapt if malformed:

//-----------------------------------------------------------------------------
// 1. DRIVER SETUP - create driver object, midi ports and detection information
//-----------------------------------------------------------------------------

// get the api's entry point
var midiremote_api = require('midiremote_api_v1')

// create the device driver main object
var deviceDriver = midiremote_api.makeDeviceDriver('PreSonus', 'FaderPort', 'WEM')

// create objects representing the hardware's MIDI ports
var midiInput = deviceDriver.mPorts.makeMidiInput()
var midiOutput = deviceDriver.mPorts.makeMidiOutput()

// define all possible namings the devices MIDI ports could have
// NOTE: Windows and MacOS handle port naming differently

deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('SimpleDevice IN')
    .expectOutputNameEquals('SimpleDevice OUT')

deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('PreSonus FP2')
    .expectOutputNameEquals('PreSonus FP2')

//-----------------------------------------------------------------------------
// 2. SURFACE LAYOUT - create control elements and midi bindings
//-----------------------------------------------------------------------------

// create control element representing your hardware's surface

var fd_Volume = deviceDriver.mSurface.makeFader(2, 0, 1, 2)
var val_FaderTouched = deviceDriver.mSurface.makeCustomVariableValue('FaderTouched')
var val_FaderOutput = deviceDriver.mSurface.makeCustomVariableValue('FaderOutput')

var kb_Rotary = deviceDriver.mSurface.makeKnob(0, 3, 1, 1)
var btn_Solo = deviceDriver.mSurface.makeButton(0, 0, 1, 1)
var btn_PrevTrack = deviceDriver.mSurface.makeButton(0, 1, 1, 1)
var btn_NextTrack = deviceDriver.mSurface.makeButton(1, 1, 1, 1)

// bind midi ports to surface elements

fd_Volume.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .bindToPitchBend(0)

val_FaderTouched.mMidiBinding
    .setInputPort(midiInput)
    .bindToNote (0, 104)

val_FaderOutput.mMidiBinding
    .setOutputPort(midOutput)
    .bindToPitchBend(0)

kb_Rotary.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 176)

btn_Solo.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 8)

btn_PrevTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 46)

btn_NextTrack.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .setOutputPort(midiOutput)
    .bindToNote (0, 47)

//-----------------------------------------------------------------------------
// 3. HOST MAPPING - create mapping pages and host bindings
//-----------------------------------------------------------------------------

// create at least one mapping page
var page = deviceDriver.mMapping.makePage('Example Mixer Page')

// create host accessing objects
var hostSelectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel

// bind surface elements to host accessing object values
page.makeActionBinding(btn_PrevTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mPrevTrack)

page.makeActionBinding(btn_NextTrack.mSurfaceValue, page.mHostAccess.mTrackSelection.mAction.mNextTrack)

// create host accessing objects
var hostSelectedMixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel

page.makeValueBinding(fd_Volume.mSurfaceValue, hostSelectedMixerChannel.mValue.mVolume)

var faderState = {
	isTouched: false,
	value: 0,
	updateHardware: function(context) {
		if(!this.isTouched)
			val_FaderOutput.setProcessValue(context, this.value)	
	}
}

fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) {
    console.log("mOnProcessValueChange: " + value.toString())
	faderState.value = value
	faderState.updateHardware(context)
}.bind({faderState})

val_FaderTouched.mOnProcessValueChange = function (context, value) {
	faderState.isTouched = value > 0
	faderState.updateHardware(context)
    if (value == 1) {
        console.log("Fader Action On")
    } else {
        console.log("Fader Action Off")        
    }
}.bind({faderState})

Hello @Jochen_Trappe ,

thx for the support. I appreciate it a lot . Unfortunately it also doesn’t work.

I tried now to strip it down to a minimum; I have defined a variable and connected it to the incoming pitch bend messages. Then the plan is to get a log message when something is incoming.

Unfortunately I see only some seldom messages and a (every time) message when I’m reaching the zero position with the fader. But only the zero position is working stable. The same procedure works fine with the rotary encoder (that uses a CC message).

To me that looks like a bug in the pitchbend implementation…

//-----------------------------------------------------------------------------
// 1. DRIVER SETUP - create driver object, midi ports and detection information
//-----------------------------------------------------------------------------

// get the api's entry point
var midiremote_api = require('midiremote_api_v1')

// create the device driver main object
var deviceDriver = midiremote_api.makeDeviceDriver('PreSonus', 'FaderPort', 'WEM')

// create objects representing the hardware's MIDI ports
var midiInput = deviceDriver.mPorts.makeMidiInput()
var midiOutput = deviceDriver.mPorts.makeMidiOutput()
  
deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput)
    .expectInputNameEquals('PreSonus FP2')
    .expectOutputNameEquals('PreSonus FP2')

//-----------------------------------------------------------------------------
// 2. SURFACE LAYOUT - create control elements and midi bindings
//-----------------------------------------------------------------------------

// create control element representing your hardware's surface
var val_FaderInput = deviceDriver.mSurface.makeCustomValueVariable('FaderInput')    
var val_RotaryInput = deviceDriver.mSurface.makeCustomValueVariable('RotaryInput')    


// bind midi ports to surface elements

val_FaderInput.mMidiBinding
    .setInputPort(midiInput)
    .bindToPitchBend(0)

val_RotaryInput.mMidiBinding
    .setInputPort(midiInput)
    .bindToControlChange (0, 0x10)

//-----------------------------------------------------------------------------
// 3. HOST MAPPING - create mapping pages and host bindings
//-----------------------------------------------------------------------------

// create at least one mapping page
var page = deviceDriver.mMapping.makePage('Example Mixer Page')

// create host accessing objects
var hostSelectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel

val_FaderInput.mOnProcessValueChange = function (context, value) {
    console.log("val_FaderInput.mOnProcessValueChange: " + value.toString())
}

val_RotaryInput.mOnProcessValueChange = function (context, value) {
    console.log("val_RotaryInput.mOnProcessValueChange: " + value.toString())
}

I can confirm, that with Cubase 12.0.10 the Pitch Bend / Motorfader works.
So my issue is solved and I proceed with writing the script.

Thx for helping.

1 Like