From 84fe2b1cb9f380187bee9fbf8fc8a5870fac20be Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 2 May 2022 11:19:37 +0200 Subject: [PATCH 1/9] Create Presonus_FaderPort --- presonus/faderport8/Presonus_FaderPort | 776 +++++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 presonus/faderport8/Presonus_FaderPort diff --git a/presonus/faderport8/Presonus_FaderPort b/presonus/faderport8/Presonus_FaderPort new file mode 100644 index 0000000..b94635d --- /dev/null +++ b/presonus/faderport8/Presonus_FaderPort @@ -0,0 +1,776 @@ +//----------------------------------------------------------------------------- +// 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 Music') + +// 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 +//----------------------------------------------------------------------------- + +/** Definitions + * + */ + +const const_FaderTouch = 0x68 + +// Upper +const const_Solo = 0x08 +const const_Mute = 0x10 +const const_Arm = 0x00 +const const_Shift = 0x46 +const const_Bypass = 0x03 +const const_Touch = 0x4D +const const_Write = 0x4B +const const_Read = 0x4A + +// Middle +const const_PrevTrack = 0x2E +const const_Rotary = 0x10 +const const_RotaryPush = 0x20 +const const_NextTrack = 0x2F + +const const_Link = 0x05 +const const_Pan = 0x2A +const const_Channel = 0x36 +const const_Scroll = 0x38 +const const_Master = 0x3A +const const_Click = 0x3B +const const_Section = 0x3C +const const_Marker = 0x3D + +// Transport +const const_Loop = 0x56 +const const_RWD = 0x5B +const const_FWD = 0x5C +const const_Stop = 0x5D +const const_Play = 0x5E +const const_Record = 0x5F + +/** Help Functions + * + */ +// helpers to turn on/off the button LEDs +function turnOnLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x7F]) +} +function turnFlashingLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x01]) +} +function turnOffLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x00]) +} +function setRGBLED(device, ledID, r, g, b) { + midiOutput.sendMidi(device, [ 0x91, ledID, r]) + midiOutput.sendMidi(device, [ 0x92, ledID, g]) + midiOutput.sendMidi(device, [ 0x93, ledID, b]) +} + +const RGB_Colors = { + c_Red: 0x01, + c_Green: 0x02, + c_Blue: 0x03 +} + +function setColorLED(device, ledID, p_color) { + if (p_color == RGB_Colors.c_Red) { + setRGBLED(device, ledID, 0x7F, 0x00, 0x00) + } else if (p_color == RGB_Colors.c_Green) { + setRGBLED(device, ledID, 0x00, 0x7F, 0x00) + } else if (p_color == RGB_Colors.c_Blue) { + setRGBLED(device, ledID, 0x00, 0x00, 0x7F) + } +} + +/** Zones + * + */ + + +var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') +var cl_fader = clz_ZoneFader.makeControlLayer('Fader') + +var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') +var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') + +var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') +var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') + +var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') +var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') + +/** FADER + * + */ + +function makeFader(p_x, p_y, p_heigh) { + var fader = {} + // create control element representing your hardware's surface + fader.fd_Volume = deviceDriver.mSurface.makeFader(p_x, p_y, 1, p_heigh) + .setTypeVertical() + fader.fd_Volume.setControlLayer(cl_fader) + + fader.val_FaderTouched = deviceDriver.mSurface.makeCustomValueVariable('FaderTouched') + fader.val_FaderOutput = deviceDriver.mSurface.makeCustomValueVariable('FaderOutput') + + var faderState = { + isTouched: false, + value: 0, + updateHardware: function(context) { + if(!this.isTouched) + if (var_Debug == true) + console.log("updateHardware: " + this.value.toString()) + fader.val_FaderOutput.setProcessValue(context, this.value) + } + } + + fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + faderState.value = value + faderState.updateHardware(context) + }.bind({faderState}) + + fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("val_FaderTouched.mOnProcessValueChange") + faderState.isTouched = value > 0 + faderState.updateHardware(context) + }.bind({faderState}) + + return fader +} + +function midiBindingFader(p_fader) { + p_fader.fd_Volume.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToPitchBend(0) + + p_fader.val_FaderTouched.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FaderTouch) + + p_fader.val_FaderOutput.mMidiBinding + .setOutputPort(midiOutput) + .bindToPitchBend(0) +} + +function hostBindingFader(p_fader, p_Page, p_pageShift) { + p_Page.makeValueBinding(fader.fd_Volume.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume) + p_pageShift.makeValueBinding(fader.fd_Volume.mSurfaceValue, pageShift.mHostAccess.mMouseCursor.mValueUnderMouse) +} + +/** UPPER BUTTONS + * + */ + +function makeUpperButtons(p_x, p_y) { + var upperButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + upperButtons.btn_Solo = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Solo.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Mute = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Mute.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Arm = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Arm.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Shift = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Shift.setControlLayer(cl_upperButtons) + x = p_x + y = y + 1 + upperButtons.btn_Bypass = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Bypass.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Touch = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Touch.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Write = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Write.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Read = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Read.setControlLayer(cl_upperButtons) + + upperButtons.btn_Solo.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Solo) + } else { + turnOffLED(context, const_Solo) + } + } + + upperButtons.btn_Mute.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Mute) + } else { + turnOffLED(context, const_Mute) + } + } + + upperButtons.btn_Arm.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Arm) + } else { + turnOffLED(context, const_Arm) + } + } + + upperButtons.btn_Bypass.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Bypass) + } else { + turnOffLED(context, const_Bypass) + } + } + + upperButtons.btn_Write.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Write) + setColorLED(context, const_Write, RGB_Colors.c_Red) + } else { + turnOffLED(context, const_Write) + } + } + + upperButtons.btn_Read.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Read) + setColorLED(context, const_Read, RGB_Colors.c_Green) + } else { + turnOffLED(context, const_Read) + } + } + + return upperButtons +} + +function midiBindingUpperButtons(p_upperButtons) { + p_upperButtons.btn_Solo.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Solo) + + p_upperButtons.btn_Mute.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Mute) + + p_upperButtons.btn_Arm.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Arm) + + p_upperButtons.btn_Shift.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Shift) + + p_upperButtons.btn_Bypass.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Bypass) + + p_upperButtons.btn_Touch.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Touch) + + p_upperButtons.btn_Write.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Write) + + p_upperButtons.btn_Read.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Read) +} + +function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { + var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel + page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) + .setTypeToggle() + page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) + page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) + .setTypeToggle() + + var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel + p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) + + p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) + .setTypeToggle() + p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) + .setTypeToggle() + + p_PageShift.mOnActivate = function(context) { + turnFlashingLED(context, const_Shift) + } + + p_Page.mOnActivate = function(context) { + turnOffLED(context, const_Shift) + } +} + +/** MIDDLE BUTTONS + * + */ +function makeMiddleButtons(p_x, p_y) { + var middleButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + middleButtons.btn_PrevTrack = deviceDriver.mSurface.makeButton(x, y + 0.25, width, heigh / 2) + .setControlLayer(cl_middleButtons) + + middleButtons.pnl_KnobPanel = deviceDriver.mSurface.makeBlindPanel(x + 1, y - 0.25, width * 2, heigh + 0.5) + + middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) + .setControlLayer(cl_middleButtons) + + middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) + .setControlLayer(cl_middleButtons) + .setShapeCircle() + + middleButtons.pnl_KnobLabel = deviceDriver.mSurface.makeLabelField(x + 1.25, y + 0.75, width * 2 - 0.5, 0.25) + .relateTo(middleButtons.kb_Rotary) + + middleButtons.btn_NextTrack = deviceDriver.mSurface.makeButton(x + 3, y + 0.25, width, heigh/2) + .setControlLayer(cl_middleButtons) + + y = y + 1.5 + middleButtons.btn_Link = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Pan = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Channel = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Scroll = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = p_x + y = y + 1 + middleButtons.btn_Master = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Click = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Section = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + + middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + } + + middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_PrevTrack) + } else { + turnOffLED(context, const_PrevTrack) + } + } + + middleButtons.btn_NextTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_NextTrack) + } else { + turnOffLED(context, const_NextTrack) + } + } + + middleButtons.btn_Link.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Link) + } else { + turnOffLED(context, const_Link) + } + } + + middleButtons.btn_Click.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Click) + } else { + turnOffLED(context, const_Click) + } + } + + return middleButtons +} + +function midiBindingMiddleButtons(p_middleButtons) { + p_middleButtons.btn_PrevTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_PrevTrack) + + p_middleButtons.kb_Rotary.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToControlChange(0, const_Rotary) + .setTypeRelativeSignedBit() + + p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote(0, const_RotaryPush) + + p_middleButtons.btn_NextTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_NextTrack) + + p_middleButtons.btn_Link.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Link) + + p_middleButtons.btn_Pan.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Pan) + + p_middleButtons.btn_Channel.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Channel) + + p_middleButtons.btn_Scroll.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Scroll) + + p_middleButtons.btn_Master.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Master) + + p_middleButtons.btn_Click.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Click) + + p_middleButtons.btn_Section.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Section) + + p_middleButtons.btn_Marker.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Marker) +} + +function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + + var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') + var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') + var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') + var subpage_Scroll = sba_SubPageArea.makeSubPage('Scroll') + var subpage_Master = sba_SubPageArea.makeSubPage('Master') + var subpage_Section = sba_SubPageArea.makeSubPage('Section') + var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') + + // Pan + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + .setSubPage(subpage_Pan) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Pan) + .setTypeToggle() + + // Channel + //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) + // .setSubPage(subpage_Scroll) + + // Scroll + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Scroll) + + // Master + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) + .setSubPage(subpage_Master) + + // Section + + // Marker + + //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + // .setSubPage(subpage_Master) + // .setTypeToggle() + + p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) + + p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) + + subpage_Pan.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOnLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Pan.mOnDeactivate = function(context) { + turnOffLED(context, const_Pan) + } + + subpage_Channel.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOnLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Channel.mOnDeactivate = function(context) { + turnOffLED(context, const_Channel) + } + + subpage_Scroll.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOnLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Scroll.mOnDeactivate = function(context) { + turnOffLED(context, const_Scroll) + } + + subpage_Master.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOnLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Master.mOnDeactivate = function(context) { + turnOffLED(context, const_Master) + } + + subpage_Section.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOnLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Section.mOnDeactivate = function(context) { + turnOffLED(context, const_Section) + } + + subpage_Marker.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOnLED(context, const_Marker) + } + subpage_Marker.mOnDeactivate = function(context) { + turnOffLED(context, const_Marker) + } +} + +/** TRANSPORT BUTTONS + * + */ + +function makeTransportButtons(p_x, p_y) { + var transportButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + transportButtons.btn_Loop = deviceDriver.mSurface.makeButton(x + 0.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_RWD = deviceDriver.mSurface.makeButton(x + 1.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_FWD = deviceDriver.mSurface.makeButton(x + 2.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Stop = deviceDriver.mSurface.makeButton(x + 0.25, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Play = deviceDriver.mSurface.makeButton(x + 1.375, y + 1.125, width * 1.25, heigh* 1.25) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Record = deviceDriver.mSurface.makeButton(x + 2.75, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Loop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Loop) + } else { + turnOffLED(context, const_Loop) + } + } + + transportButtons.btn_Stop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Stop) + } else { + turnOffLED(context, const_Stop) + } + } + + transportButtons.btn_Play.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Play) + } else { + turnOnLED(context, const_Stop) + turnOffLED(context, const_Play) + } + } + + transportButtons.btn_Record.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Record) + turnOnLED(context, const_Play) + } else { + turnOffLED(context, const_Record) + } + } + + transportButtons.btn_RWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_RWD) + } else { + turnOnLED(context, const_RWD) + } + } + + transportButtons.btn_FWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_FWD) + } else { + turnOnLED(context, const_FWD) + } + } + + return transportButtons +} + +function midiBindingTransportButtons(p_transportButtons) { + p_transportButtons.btn_Loop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Loop) + + p_transportButtons.btn_RWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_RWD) + + p_transportButtons.btn_FWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FWD) + + p_transportButtons.btn_Stop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Stop) + + p_transportButtons.btn_Play.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Play) + + p_transportButtons.btn_Record.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Record) +} + +function hostBindingTransportButtons(p_transportButtons, p_Page, pageShift) { + var transport = page.mHostAccess.mTransport.mValue + page.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport.mCycleActive) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport.mRewind) + page.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport.mForward) + page.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport.mStop) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport.mStart) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport.mRecord) + .setTypeToggle() + + var transport_pageShift = pageShift.mHostAccess.mTransport.mValue + pageShift.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport_pageShift.mCycleActive) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport_pageShift.mRewind) + pageShift.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport_pageShift.mForward) + pageShift.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport_pageShift.mStop) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport_pageShift.mStart) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport_pageShift.mRecord) + .setTypeToggle() +} + +/** MAIN + * + */ +var page = deviceDriver.mMapping.makePage('PreSonus FP2 MAIN') +var pageShift = deviceDriver.mMapping.makePage('PreSonus FP2 SHIFT') +var var_Debug = false + +var fader = makeFader(0, 0, 9) +midiBindingFader(fader) +hostBindingFader(fader, page, pageShift) + +var upperButtons = makeUpperButtons(2, 0) +midiBindingUpperButtons(upperButtons) +hostBindingUpperButtons(upperButtons, page, pageShift) + +var middleButtons = makeMiddleButtons(2, 3) +midiBindingMiddleButtons(middleButtons) +hostBindingMiddleButtons(middleButtons, page, pageShift) + +var transportButtons = makeTransportButtons(2, 7) +midiBindingTransportButtons(transportButtons) +hostBindingTransportButtons(transportButtons, page, pageShift) From c1e0cc8305d6faca482466cb7c5a2d12c217e75e Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 2 May 2022 11:21:05 +0200 Subject: [PATCH 2/9] Delete Presonus_FaderPort --- presonus/faderport8/Presonus_FaderPort | 776 ------------------------- 1 file changed, 776 deletions(-) delete mode 100644 presonus/faderport8/Presonus_FaderPort diff --git a/presonus/faderport8/Presonus_FaderPort b/presonus/faderport8/Presonus_FaderPort deleted file mode 100644 index b94635d..0000000 --- a/presonus/faderport8/Presonus_FaderPort +++ /dev/null @@ -1,776 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 Music') - -// 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 -//----------------------------------------------------------------------------- - -/** Definitions - * - */ - -const const_FaderTouch = 0x68 - -// Upper -const const_Solo = 0x08 -const const_Mute = 0x10 -const const_Arm = 0x00 -const const_Shift = 0x46 -const const_Bypass = 0x03 -const const_Touch = 0x4D -const const_Write = 0x4B -const const_Read = 0x4A - -// Middle -const const_PrevTrack = 0x2E -const const_Rotary = 0x10 -const const_RotaryPush = 0x20 -const const_NextTrack = 0x2F - -const const_Link = 0x05 -const const_Pan = 0x2A -const const_Channel = 0x36 -const const_Scroll = 0x38 -const const_Master = 0x3A -const const_Click = 0x3B -const const_Section = 0x3C -const const_Marker = 0x3D - -// Transport -const const_Loop = 0x56 -const const_RWD = 0x5B -const const_FWD = 0x5C -const const_Stop = 0x5D -const const_Play = 0x5E -const const_Record = 0x5F - -/** Help Functions - * - */ -// helpers to turn on/off the button LEDs -function turnOnLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x7F]) -} -function turnFlashingLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x01]) -} -function turnOffLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x00]) -} -function setRGBLED(device, ledID, r, g, b) { - midiOutput.sendMidi(device, [ 0x91, ledID, r]) - midiOutput.sendMidi(device, [ 0x92, ledID, g]) - midiOutput.sendMidi(device, [ 0x93, ledID, b]) -} - -const RGB_Colors = { - c_Red: 0x01, - c_Green: 0x02, - c_Blue: 0x03 -} - -function setColorLED(device, ledID, p_color) { - if (p_color == RGB_Colors.c_Red) { - setRGBLED(device, ledID, 0x7F, 0x00, 0x00) - } else if (p_color == RGB_Colors.c_Green) { - setRGBLED(device, ledID, 0x00, 0x7F, 0x00) - } else if (p_color == RGB_Colors.c_Blue) { - setRGBLED(device, ledID, 0x00, 0x00, 0x7F) - } -} - -/** Zones - * - */ - - -var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') -var cl_fader = clz_ZoneFader.makeControlLayer('Fader') - -var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') -var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') - -var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') -var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') - -var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') -var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') - -/** FADER - * - */ - -function makeFader(p_x, p_y, p_heigh) { - var fader = {} - // create control element representing your hardware's surface - fader.fd_Volume = deviceDriver.mSurface.makeFader(p_x, p_y, 1, p_heigh) - .setTypeVertical() - fader.fd_Volume.setControlLayer(cl_fader) - - fader.val_FaderTouched = deviceDriver.mSurface.makeCustomValueVariable('FaderTouched') - fader.val_FaderOutput = deviceDriver.mSurface.makeCustomValueVariable('FaderOutput') - - var faderState = { - isTouched: false, - value: 0, - updateHardware: function(context) { - if(!this.isTouched) - if (var_Debug == true) - console.log("updateHardware: " + this.value.toString()) - fader.val_FaderOutput.setProcessValue(context, this.value) - } - } - - fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) - faderState.value = value - faderState.updateHardware(context) - }.bind({faderState}) - - fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("val_FaderTouched.mOnProcessValueChange") - faderState.isTouched = value > 0 - faderState.updateHardware(context) - }.bind({faderState}) - - return fader -} - -function midiBindingFader(p_fader) { - p_fader.fd_Volume.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToPitchBend(0) - - p_fader.val_FaderTouched.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_FaderTouch) - - p_fader.val_FaderOutput.mMidiBinding - .setOutputPort(midiOutput) - .bindToPitchBend(0) -} - -function hostBindingFader(p_fader, p_Page, p_pageShift) { - p_Page.makeValueBinding(fader.fd_Volume.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume) - p_pageShift.makeValueBinding(fader.fd_Volume.mSurfaceValue, pageShift.mHostAccess.mMouseCursor.mValueUnderMouse) -} - -/** UPPER BUTTONS - * - */ - -function makeUpperButtons(p_x, p_y) { - var upperButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - upperButtons.btn_Solo = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Solo.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Mute = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Mute.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Arm = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Arm.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Shift = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Shift.setControlLayer(cl_upperButtons) - x = p_x - y = y + 1 - upperButtons.btn_Bypass = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Bypass.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Touch = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Touch.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Write = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Write.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Read = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Read.setControlLayer(cl_upperButtons) - - upperButtons.btn_Solo.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Solo) - } else { - turnOffLED(context, const_Solo) - } - } - - upperButtons.btn_Mute.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Mute) - } else { - turnOffLED(context, const_Mute) - } - } - - upperButtons.btn_Arm.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Arm) - } else { - turnOffLED(context, const_Arm) - } - } - - upperButtons.btn_Bypass.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Bypass) - } else { - turnOffLED(context, const_Bypass) - } - } - - upperButtons.btn_Write.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Write) - setColorLED(context, const_Write, RGB_Colors.c_Red) - } else { - turnOffLED(context, const_Write) - } - } - - upperButtons.btn_Read.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Read) - setColorLED(context, const_Read, RGB_Colors.c_Green) - } else { - turnOffLED(context, const_Read) - } - } - - return upperButtons -} - -function midiBindingUpperButtons(p_upperButtons) { - p_upperButtons.btn_Solo.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Solo) - - p_upperButtons.btn_Mute.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Mute) - - p_upperButtons.btn_Arm.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Arm) - - p_upperButtons.btn_Shift.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Shift) - - p_upperButtons.btn_Bypass.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Bypass) - - p_upperButtons.btn_Touch.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Touch) - - p_upperButtons.btn_Write.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Write) - - p_upperButtons.btn_Read.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Read) -} - -function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { - var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel - page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) - .setTypeToggle() - page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) - page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) - .setTypeToggle() - - var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel - p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) - - p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) - .setTypeToggle() - p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) - .setTypeToggle() - - p_PageShift.mOnActivate = function(context) { - turnFlashingLED(context, const_Shift) - } - - p_Page.mOnActivate = function(context) { - turnOffLED(context, const_Shift) - } -} - -/** MIDDLE BUTTONS - * - */ -function makeMiddleButtons(p_x, p_y) { - var middleButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - middleButtons.btn_PrevTrack = deviceDriver.mSurface.makeButton(x, y + 0.25, width, heigh / 2) - .setControlLayer(cl_middleButtons) - - middleButtons.pnl_KnobPanel = deviceDriver.mSurface.makeBlindPanel(x + 1, y - 0.25, width * 2, heigh + 0.5) - - middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) - .setControlLayer(cl_middleButtons) - - middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) - .setControlLayer(cl_middleButtons) - .setShapeCircle() - - middleButtons.pnl_KnobLabel = deviceDriver.mSurface.makeLabelField(x + 1.25, y + 0.75, width * 2 - 0.5, 0.25) - .relateTo(middleButtons.kb_Rotary) - - middleButtons.btn_NextTrack = deviceDriver.mSurface.makeButton(x + 3, y + 0.25, width, heigh/2) - .setControlLayer(cl_middleButtons) - - y = y + 1.5 - middleButtons.btn_Link = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Pan = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Channel = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Scroll = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = p_x - y = y + 1 - middleButtons.btn_Master = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Click = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Section = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - - middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) - } - - middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_PrevTrack) - } else { - turnOffLED(context, const_PrevTrack) - } - } - - middleButtons.btn_NextTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_NextTrack) - } else { - turnOffLED(context, const_NextTrack) - } - } - - middleButtons.btn_Link.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Link) - } else { - turnOffLED(context, const_Link) - } - } - - middleButtons.btn_Click.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Click) - } else { - turnOffLED(context, const_Click) - } - } - - return middleButtons -} - -function midiBindingMiddleButtons(p_middleButtons) { - p_middleButtons.btn_PrevTrack.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_PrevTrack) - - p_middleButtons.kb_Rotary.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToControlChange(0, const_Rotary) - .setTypeRelativeSignedBit() - - p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote(0, const_RotaryPush) - - p_middleButtons.btn_NextTrack.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_NextTrack) - - p_middleButtons.btn_Link.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Link) - - p_middleButtons.btn_Pan.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Pan) - - p_middleButtons.btn_Channel.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Channel) - - p_middleButtons.btn_Scroll.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Scroll) - - p_middleButtons.btn_Master.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Master) - - p_middleButtons.btn_Click.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Click) - - p_middleButtons.btn_Section.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Section) - - p_middleButtons.btn_Marker.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Marker) -} - -function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { - p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) - p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) - - var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') - var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') - var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') - var subpage_Scroll = sba_SubPageArea.makeSubPage('Scroll') - var subpage_Master = sba_SubPageArea.makeSubPage('Master') - var subpage_Section = sba_SubPageArea.makeSubPage('Section') - var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') - - // Pan - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) - .setSubPage(subpage_Pan) - p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) - .setSubPage(subpage_Pan) - .setTypeToggle() - - // Channel - //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) - // .setSubPage(subpage_Scroll) - - // Scroll - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) - .setSubPage(subpage_Scroll) - - // Master - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) - .setSubPage(subpage_Master) - - // Section - - // Marker - - //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) - // .setSubPage(subpage_Master) - // .setTypeToggle() - - p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) - .setTypeToggle() - - p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) - - p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) - .setTypeToggle() - - p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) - - subpage_Pan.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOnLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Pan.mOnDeactivate = function(context) { - turnOffLED(context, const_Pan) - } - - subpage_Channel.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOnLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Channel.mOnDeactivate = function(context) { - turnOffLED(context, const_Channel) - } - - subpage_Scroll.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOnLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Scroll.mOnDeactivate = function(context) { - turnOffLED(context, const_Scroll) - } - - subpage_Master.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOnLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Master.mOnDeactivate = function(context) { - turnOffLED(context, const_Master) - } - - subpage_Section.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOnLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Section.mOnDeactivate = function(context) { - turnOffLED(context, const_Section) - } - - subpage_Marker.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOnLED(context, const_Marker) - } - subpage_Marker.mOnDeactivate = function(context) { - turnOffLED(context, const_Marker) - } -} - -/** TRANSPORT BUTTONS - * - */ - -function makeTransportButtons(p_x, p_y) { - var transportButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - transportButtons.btn_Loop = deviceDriver.mSurface.makeButton(x + 0.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_RWD = deviceDriver.mSurface.makeButton(x + 1.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_FWD = deviceDriver.mSurface.makeButton(x + 2.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Stop = deviceDriver.mSurface.makeButton(x + 0.25, y + 1, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Play = deviceDriver.mSurface.makeButton(x + 1.375, y + 1.125, width * 1.25, heigh* 1.25) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Record = deviceDriver.mSurface.makeButton(x + 2.75, y + 1, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Loop.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Loop) - } else { - turnOffLED(context, const_Loop) - } - } - - transportButtons.btn_Stop.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Stop) - } else { - turnOffLED(context, const_Stop) - } - } - - transportButtons.btn_Play.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOffLED(context, const_Stop) - turnOnLED(context, const_Play) - } else { - turnOnLED(context, const_Stop) - turnOffLED(context, const_Play) - } - } - - transportButtons.btn_Record.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOffLED(context, const_Stop) - turnOnLED(context, const_Record) - turnOnLED(context, const_Play) - } else { - turnOffLED(context, const_Record) - } - } - - transportButtons.btn_RWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (!value) { - turnOffLED(context, const_RWD) - } else { - turnOnLED(context, const_RWD) - } - } - - transportButtons.btn_FWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (!value) { - turnOffLED(context, const_FWD) - } else { - turnOnLED(context, const_FWD) - } - } - - return transportButtons -} - -function midiBindingTransportButtons(p_transportButtons) { - p_transportButtons.btn_Loop.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Loop) - - p_transportButtons.btn_RWD.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_RWD) - - p_transportButtons.btn_FWD.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_FWD) - - p_transportButtons.btn_Stop.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Stop) - - p_transportButtons.btn_Play.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Play) - - p_transportButtons.btn_Record.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Record) -} - -function hostBindingTransportButtons(p_transportButtons, p_Page, pageShift) { - var transport = page.mHostAccess.mTransport.mValue - page.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport.mCycleActive) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport.mRewind) - page.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport.mForward) - page.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport.mStop) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport.mStart) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport.mRecord) - .setTypeToggle() - - var transport_pageShift = pageShift.mHostAccess.mTransport.mValue - pageShift.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport_pageShift.mCycleActive) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport_pageShift.mRewind) - pageShift.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport_pageShift.mForward) - pageShift.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport_pageShift.mStop) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport_pageShift.mStart) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport_pageShift.mRecord) - .setTypeToggle() -} - -/** MAIN - * - */ -var page = deviceDriver.mMapping.makePage('PreSonus FP2 MAIN') -var pageShift = deviceDriver.mMapping.makePage('PreSonus FP2 SHIFT') -var var_Debug = false - -var fader = makeFader(0, 0, 9) -midiBindingFader(fader) -hostBindingFader(fader, page, pageShift) - -var upperButtons = makeUpperButtons(2, 0) -midiBindingUpperButtons(upperButtons) -hostBindingUpperButtons(upperButtons, page, pageShift) - -var middleButtons = makeMiddleButtons(2, 3) -midiBindingMiddleButtons(middleButtons) -hostBindingMiddleButtons(middleButtons, page, pageShift) - -var transportButtons = makeTransportButtons(2, 7) -midiBindingTransportButtons(transportButtons) -hostBindingTransportButtons(transportButtons, page, pageShift) From 775dc1406009069cff7249c583138312cb7e204a Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 2 May 2022 11:22:03 +0200 Subject: [PATCH 3/9] Create Presonus_FaderPort --- presonus/faderport/Presonus_FaderPort | 776 ++++++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 presonus/faderport/Presonus_FaderPort diff --git a/presonus/faderport/Presonus_FaderPort b/presonus/faderport/Presonus_FaderPort new file mode 100644 index 0000000..b94635d --- /dev/null +++ b/presonus/faderport/Presonus_FaderPort @@ -0,0 +1,776 @@ +//----------------------------------------------------------------------------- +// 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 Music') + +// 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 +//----------------------------------------------------------------------------- + +/** Definitions + * + */ + +const const_FaderTouch = 0x68 + +// Upper +const const_Solo = 0x08 +const const_Mute = 0x10 +const const_Arm = 0x00 +const const_Shift = 0x46 +const const_Bypass = 0x03 +const const_Touch = 0x4D +const const_Write = 0x4B +const const_Read = 0x4A + +// Middle +const const_PrevTrack = 0x2E +const const_Rotary = 0x10 +const const_RotaryPush = 0x20 +const const_NextTrack = 0x2F + +const const_Link = 0x05 +const const_Pan = 0x2A +const const_Channel = 0x36 +const const_Scroll = 0x38 +const const_Master = 0x3A +const const_Click = 0x3B +const const_Section = 0x3C +const const_Marker = 0x3D + +// Transport +const const_Loop = 0x56 +const const_RWD = 0x5B +const const_FWD = 0x5C +const const_Stop = 0x5D +const const_Play = 0x5E +const const_Record = 0x5F + +/** Help Functions + * + */ +// helpers to turn on/off the button LEDs +function turnOnLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x7F]) +} +function turnFlashingLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x01]) +} +function turnOffLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x00]) +} +function setRGBLED(device, ledID, r, g, b) { + midiOutput.sendMidi(device, [ 0x91, ledID, r]) + midiOutput.sendMidi(device, [ 0x92, ledID, g]) + midiOutput.sendMidi(device, [ 0x93, ledID, b]) +} + +const RGB_Colors = { + c_Red: 0x01, + c_Green: 0x02, + c_Blue: 0x03 +} + +function setColorLED(device, ledID, p_color) { + if (p_color == RGB_Colors.c_Red) { + setRGBLED(device, ledID, 0x7F, 0x00, 0x00) + } else if (p_color == RGB_Colors.c_Green) { + setRGBLED(device, ledID, 0x00, 0x7F, 0x00) + } else if (p_color == RGB_Colors.c_Blue) { + setRGBLED(device, ledID, 0x00, 0x00, 0x7F) + } +} + +/** Zones + * + */ + + +var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') +var cl_fader = clz_ZoneFader.makeControlLayer('Fader') + +var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') +var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') + +var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') +var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') + +var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') +var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') + +/** FADER + * + */ + +function makeFader(p_x, p_y, p_heigh) { + var fader = {} + // create control element representing your hardware's surface + fader.fd_Volume = deviceDriver.mSurface.makeFader(p_x, p_y, 1, p_heigh) + .setTypeVertical() + fader.fd_Volume.setControlLayer(cl_fader) + + fader.val_FaderTouched = deviceDriver.mSurface.makeCustomValueVariable('FaderTouched') + fader.val_FaderOutput = deviceDriver.mSurface.makeCustomValueVariable('FaderOutput') + + var faderState = { + isTouched: false, + value: 0, + updateHardware: function(context) { + if(!this.isTouched) + if (var_Debug == true) + console.log("updateHardware: " + this.value.toString()) + fader.val_FaderOutput.setProcessValue(context, this.value) + } + } + + fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + faderState.value = value + faderState.updateHardware(context) + }.bind({faderState}) + + fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("val_FaderTouched.mOnProcessValueChange") + faderState.isTouched = value > 0 + faderState.updateHardware(context) + }.bind({faderState}) + + return fader +} + +function midiBindingFader(p_fader) { + p_fader.fd_Volume.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToPitchBend(0) + + p_fader.val_FaderTouched.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FaderTouch) + + p_fader.val_FaderOutput.mMidiBinding + .setOutputPort(midiOutput) + .bindToPitchBend(0) +} + +function hostBindingFader(p_fader, p_Page, p_pageShift) { + p_Page.makeValueBinding(fader.fd_Volume.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume) + p_pageShift.makeValueBinding(fader.fd_Volume.mSurfaceValue, pageShift.mHostAccess.mMouseCursor.mValueUnderMouse) +} + +/** UPPER BUTTONS + * + */ + +function makeUpperButtons(p_x, p_y) { + var upperButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + upperButtons.btn_Solo = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Solo.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Mute = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Mute.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Arm = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Arm.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Shift = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Shift.setControlLayer(cl_upperButtons) + x = p_x + y = y + 1 + upperButtons.btn_Bypass = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Bypass.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Touch = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Touch.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Write = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Write.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Read = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Read.setControlLayer(cl_upperButtons) + + upperButtons.btn_Solo.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Solo) + } else { + turnOffLED(context, const_Solo) + } + } + + upperButtons.btn_Mute.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Mute) + } else { + turnOffLED(context, const_Mute) + } + } + + upperButtons.btn_Arm.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Arm) + } else { + turnOffLED(context, const_Arm) + } + } + + upperButtons.btn_Bypass.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Bypass) + } else { + turnOffLED(context, const_Bypass) + } + } + + upperButtons.btn_Write.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Write) + setColorLED(context, const_Write, RGB_Colors.c_Red) + } else { + turnOffLED(context, const_Write) + } + } + + upperButtons.btn_Read.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Read) + setColorLED(context, const_Read, RGB_Colors.c_Green) + } else { + turnOffLED(context, const_Read) + } + } + + return upperButtons +} + +function midiBindingUpperButtons(p_upperButtons) { + p_upperButtons.btn_Solo.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Solo) + + p_upperButtons.btn_Mute.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Mute) + + p_upperButtons.btn_Arm.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Arm) + + p_upperButtons.btn_Shift.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Shift) + + p_upperButtons.btn_Bypass.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Bypass) + + p_upperButtons.btn_Touch.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Touch) + + p_upperButtons.btn_Write.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Write) + + p_upperButtons.btn_Read.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Read) +} + +function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { + var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel + page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) + .setTypeToggle() + page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) + page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) + .setTypeToggle() + + var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel + p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) + + p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) + .setTypeToggle() + p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) + .setTypeToggle() + + p_PageShift.mOnActivate = function(context) { + turnFlashingLED(context, const_Shift) + } + + p_Page.mOnActivate = function(context) { + turnOffLED(context, const_Shift) + } +} + +/** MIDDLE BUTTONS + * + */ +function makeMiddleButtons(p_x, p_y) { + var middleButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + middleButtons.btn_PrevTrack = deviceDriver.mSurface.makeButton(x, y + 0.25, width, heigh / 2) + .setControlLayer(cl_middleButtons) + + middleButtons.pnl_KnobPanel = deviceDriver.mSurface.makeBlindPanel(x + 1, y - 0.25, width * 2, heigh + 0.5) + + middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) + .setControlLayer(cl_middleButtons) + + middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) + .setControlLayer(cl_middleButtons) + .setShapeCircle() + + middleButtons.pnl_KnobLabel = deviceDriver.mSurface.makeLabelField(x + 1.25, y + 0.75, width * 2 - 0.5, 0.25) + .relateTo(middleButtons.kb_Rotary) + + middleButtons.btn_NextTrack = deviceDriver.mSurface.makeButton(x + 3, y + 0.25, width, heigh/2) + .setControlLayer(cl_middleButtons) + + y = y + 1.5 + middleButtons.btn_Link = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Pan = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Channel = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Scroll = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = p_x + y = y + 1 + middleButtons.btn_Master = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Click = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Section = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + + middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + } + + middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_PrevTrack) + } else { + turnOffLED(context, const_PrevTrack) + } + } + + middleButtons.btn_NextTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_NextTrack) + } else { + turnOffLED(context, const_NextTrack) + } + } + + middleButtons.btn_Link.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Link) + } else { + turnOffLED(context, const_Link) + } + } + + middleButtons.btn_Click.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Click) + } else { + turnOffLED(context, const_Click) + } + } + + return middleButtons +} + +function midiBindingMiddleButtons(p_middleButtons) { + p_middleButtons.btn_PrevTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_PrevTrack) + + p_middleButtons.kb_Rotary.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToControlChange(0, const_Rotary) + .setTypeRelativeSignedBit() + + p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote(0, const_RotaryPush) + + p_middleButtons.btn_NextTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_NextTrack) + + p_middleButtons.btn_Link.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Link) + + p_middleButtons.btn_Pan.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Pan) + + p_middleButtons.btn_Channel.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Channel) + + p_middleButtons.btn_Scroll.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Scroll) + + p_middleButtons.btn_Master.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Master) + + p_middleButtons.btn_Click.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Click) + + p_middleButtons.btn_Section.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Section) + + p_middleButtons.btn_Marker.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Marker) +} + +function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + + var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') + var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') + var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') + var subpage_Scroll = sba_SubPageArea.makeSubPage('Scroll') + var subpage_Master = sba_SubPageArea.makeSubPage('Master') + var subpage_Section = sba_SubPageArea.makeSubPage('Section') + var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') + + // Pan + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + .setSubPage(subpage_Pan) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Pan) + .setTypeToggle() + + // Channel + //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) + // .setSubPage(subpage_Scroll) + + // Scroll + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Scroll) + + // Master + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) + .setSubPage(subpage_Master) + + // Section + + // Marker + + //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + // .setSubPage(subpage_Master) + // .setTypeToggle() + + p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) + + p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) + + subpage_Pan.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOnLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Pan.mOnDeactivate = function(context) { + turnOffLED(context, const_Pan) + } + + subpage_Channel.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOnLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Channel.mOnDeactivate = function(context) { + turnOffLED(context, const_Channel) + } + + subpage_Scroll.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOnLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Scroll.mOnDeactivate = function(context) { + turnOffLED(context, const_Scroll) + } + + subpage_Master.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOnLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Master.mOnDeactivate = function(context) { + turnOffLED(context, const_Master) + } + + subpage_Section.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOnLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Section.mOnDeactivate = function(context) { + turnOffLED(context, const_Section) + } + + subpage_Marker.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOnLED(context, const_Marker) + } + subpage_Marker.mOnDeactivate = function(context) { + turnOffLED(context, const_Marker) + } +} + +/** TRANSPORT BUTTONS + * + */ + +function makeTransportButtons(p_x, p_y) { + var transportButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + transportButtons.btn_Loop = deviceDriver.mSurface.makeButton(x + 0.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_RWD = deviceDriver.mSurface.makeButton(x + 1.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_FWD = deviceDriver.mSurface.makeButton(x + 2.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Stop = deviceDriver.mSurface.makeButton(x + 0.25, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Play = deviceDriver.mSurface.makeButton(x + 1.375, y + 1.125, width * 1.25, heigh* 1.25) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Record = deviceDriver.mSurface.makeButton(x + 2.75, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Loop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Loop) + } else { + turnOffLED(context, const_Loop) + } + } + + transportButtons.btn_Stop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Stop) + } else { + turnOffLED(context, const_Stop) + } + } + + transportButtons.btn_Play.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Play) + } else { + turnOnLED(context, const_Stop) + turnOffLED(context, const_Play) + } + } + + transportButtons.btn_Record.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Record) + turnOnLED(context, const_Play) + } else { + turnOffLED(context, const_Record) + } + } + + transportButtons.btn_RWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_RWD) + } else { + turnOnLED(context, const_RWD) + } + } + + transportButtons.btn_FWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_FWD) + } else { + turnOnLED(context, const_FWD) + } + } + + return transportButtons +} + +function midiBindingTransportButtons(p_transportButtons) { + p_transportButtons.btn_Loop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Loop) + + p_transportButtons.btn_RWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_RWD) + + p_transportButtons.btn_FWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FWD) + + p_transportButtons.btn_Stop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Stop) + + p_transportButtons.btn_Play.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Play) + + p_transportButtons.btn_Record.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Record) +} + +function hostBindingTransportButtons(p_transportButtons, p_Page, pageShift) { + var transport = page.mHostAccess.mTransport.mValue + page.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport.mCycleActive) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport.mRewind) + page.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport.mForward) + page.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport.mStop) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport.mStart) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport.mRecord) + .setTypeToggle() + + var transport_pageShift = pageShift.mHostAccess.mTransport.mValue + pageShift.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport_pageShift.mCycleActive) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport_pageShift.mRewind) + pageShift.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport_pageShift.mForward) + pageShift.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport_pageShift.mStop) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport_pageShift.mStart) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport_pageShift.mRecord) + .setTypeToggle() +} + +/** MAIN + * + */ +var page = deviceDriver.mMapping.makePage('PreSonus FP2 MAIN') +var pageShift = deviceDriver.mMapping.makePage('PreSonus FP2 SHIFT') +var var_Debug = false + +var fader = makeFader(0, 0, 9) +midiBindingFader(fader) +hostBindingFader(fader, page, pageShift) + +var upperButtons = makeUpperButtons(2, 0) +midiBindingUpperButtons(upperButtons) +hostBindingUpperButtons(upperButtons, page, pageShift) + +var middleButtons = makeMiddleButtons(2, 3) +midiBindingMiddleButtons(middleButtons) +hostBindingMiddleButtons(middleButtons, page, pageShift) + +var transportButtons = makeTransportButtons(2, 7) +midiBindingTransportButtons(transportButtons) +hostBindingTransportButtons(transportButtons, page, pageShift) From 84ea898772bce589ba484844bb4cf28e291ca272 Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 2 May 2022 11:23:24 +0200 Subject: [PATCH 4/9] Delete Presonus_FaderPort --- presonus/faderport/Presonus_FaderPort | 776 -------------------------- 1 file changed, 776 deletions(-) delete mode 100644 presonus/faderport/Presonus_FaderPort diff --git a/presonus/faderport/Presonus_FaderPort b/presonus/faderport/Presonus_FaderPort deleted file mode 100644 index b94635d..0000000 --- a/presonus/faderport/Presonus_FaderPort +++ /dev/null @@ -1,776 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 Music') - -// 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 -//----------------------------------------------------------------------------- - -/** Definitions - * - */ - -const const_FaderTouch = 0x68 - -// Upper -const const_Solo = 0x08 -const const_Mute = 0x10 -const const_Arm = 0x00 -const const_Shift = 0x46 -const const_Bypass = 0x03 -const const_Touch = 0x4D -const const_Write = 0x4B -const const_Read = 0x4A - -// Middle -const const_PrevTrack = 0x2E -const const_Rotary = 0x10 -const const_RotaryPush = 0x20 -const const_NextTrack = 0x2F - -const const_Link = 0x05 -const const_Pan = 0x2A -const const_Channel = 0x36 -const const_Scroll = 0x38 -const const_Master = 0x3A -const const_Click = 0x3B -const const_Section = 0x3C -const const_Marker = 0x3D - -// Transport -const const_Loop = 0x56 -const const_RWD = 0x5B -const const_FWD = 0x5C -const const_Stop = 0x5D -const const_Play = 0x5E -const const_Record = 0x5F - -/** Help Functions - * - */ -// helpers to turn on/off the button LEDs -function turnOnLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x7F]) -} -function turnFlashingLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x01]) -} -function turnOffLED(device, ledID) -{ - midiOutput.sendMidi(device, [ 0x90, ledID, 0x00]) -} -function setRGBLED(device, ledID, r, g, b) { - midiOutput.sendMidi(device, [ 0x91, ledID, r]) - midiOutput.sendMidi(device, [ 0x92, ledID, g]) - midiOutput.sendMidi(device, [ 0x93, ledID, b]) -} - -const RGB_Colors = { - c_Red: 0x01, - c_Green: 0x02, - c_Blue: 0x03 -} - -function setColorLED(device, ledID, p_color) { - if (p_color == RGB_Colors.c_Red) { - setRGBLED(device, ledID, 0x7F, 0x00, 0x00) - } else if (p_color == RGB_Colors.c_Green) { - setRGBLED(device, ledID, 0x00, 0x7F, 0x00) - } else if (p_color == RGB_Colors.c_Blue) { - setRGBLED(device, ledID, 0x00, 0x00, 0x7F) - } -} - -/** Zones - * - */ - - -var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') -var cl_fader = clz_ZoneFader.makeControlLayer('Fader') - -var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') -var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') - -var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') -var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') - -var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') -var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') - -/** FADER - * - */ - -function makeFader(p_x, p_y, p_heigh) { - var fader = {} - // create control element representing your hardware's surface - fader.fd_Volume = deviceDriver.mSurface.makeFader(p_x, p_y, 1, p_heigh) - .setTypeVertical() - fader.fd_Volume.setControlLayer(cl_fader) - - fader.val_FaderTouched = deviceDriver.mSurface.makeCustomValueVariable('FaderTouched') - fader.val_FaderOutput = deviceDriver.mSurface.makeCustomValueVariable('FaderOutput') - - var faderState = { - isTouched: false, - value: 0, - updateHardware: function(context) { - if(!this.isTouched) - if (var_Debug == true) - console.log("updateHardware: " + this.value.toString()) - fader.val_FaderOutput.setProcessValue(context, this.value) - } - } - - fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) - faderState.value = value - faderState.updateHardware(context) - }.bind({faderState}) - - fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("val_FaderTouched.mOnProcessValueChange") - faderState.isTouched = value > 0 - faderState.updateHardware(context) - }.bind({faderState}) - - return fader -} - -function midiBindingFader(p_fader) { - p_fader.fd_Volume.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToPitchBend(0) - - p_fader.val_FaderTouched.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_FaderTouch) - - p_fader.val_FaderOutput.mMidiBinding - .setOutputPort(midiOutput) - .bindToPitchBend(0) -} - -function hostBindingFader(p_fader, p_Page, p_pageShift) { - p_Page.makeValueBinding(fader.fd_Volume.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume) - p_pageShift.makeValueBinding(fader.fd_Volume.mSurfaceValue, pageShift.mHostAccess.mMouseCursor.mValueUnderMouse) -} - -/** UPPER BUTTONS - * - */ - -function makeUpperButtons(p_x, p_y) { - var upperButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - upperButtons.btn_Solo = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Solo.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Mute = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Mute.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Arm = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Arm.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Shift = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Shift.setControlLayer(cl_upperButtons) - x = p_x - y = y + 1 - upperButtons.btn_Bypass = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Bypass.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Touch = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Touch.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Write = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Write.setControlLayer(cl_upperButtons) - x = x + 1 - upperButtons.btn_Read = deviceDriver.mSurface.makeButton(x, y, width, heigh) - upperButtons.btn_Read.setControlLayer(cl_upperButtons) - - upperButtons.btn_Solo.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Solo) - } else { - turnOffLED(context, const_Solo) - } - } - - upperButtons.btn_Mute.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Mute) - } else { - turnOffLED(context, const_Mute) - } - } - - upperButtons.btn_Arm.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Arm) - } else { - turnOffLED(context, const_Arm) - } - } - - upperButtons.btn_Bypass.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Bypass) - } else { - turnOffLED(context, const_Bypass) - } - } - - upperButtons.btn_Write.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Write) - setColorLED(context, const_Write, RGB_Colors.c_Red) - } else { - turnOffLED(context, const_Write) - } - } - - upperButtons.btn_Read.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Read) - setColorLED(context, const_Read, RGB_Colors.c_Green) - } else { - turnOffLED(context, const_Read) - } - } - - return upperButtons -} - -function midiBindingUpperButtons(p_upperButtons) { - p_upperButtons.btn_Solo.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Solo) - - p_upperButtons.btn_Mute.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Mute) - - p_upperButtons.btn_Arm.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Arm) - - p_upperButtons.btn_Shift.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Shift) - - p_upperButtons.btn_Bypass.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Bypass) - - p_upperButtons.btn_Touch.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Touch) - - p_upperButtons.btn_Write.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Write) - - p_upperButtons.btn_Read.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Read) -} - -function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { - var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel - page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) - .setTypeToggle() - page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) - page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) - .setTypeToggle() - - var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel - p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) - - p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) - .setTypeToggle() - p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) - .setTypeToggle() - - p_PageShift.mOnActivate = function(context) { - turnFlashingLED(context, const_Shift) - } - - p_Page.mOnActivate = function(context) { - turnOffLED(context, const_Shift) - } -} - -/** MIDDLE BUTTONS - * - */ -function makeMiddleButtons(p_x, p_y) { - var middleButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - middleButtons.btn_PrevTrack = deviceDriver.mSurface.makeButton(x, y + 0.25, width, heigh / 2) - .setControlLayer(cl_middleButtons) - - middleButtons.pnl_KnobPanel = deviceDriver.mSurface.makeBlindPanel(x + 1, y - 0.25, width * 2, heigh + 0.5) - - middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) - .setControlLayer(cl_middleButtons) - - middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) - .setControlLayer(cl_middleButtons) - .setShapeCircle() - - middleButtons.pnl_KnobLabel = deviceDriver.mSurface.makeLabelField(x + 1.25, y + 0.75, width * 2 - 0.5, 0.25) - .relateTo(middleButtons.kb_Rotary) - - middleButtons.btn_NextTrack = deviceDriver.mSurface.makeButton(x + 3, y + 0.25, width, heigh/2) - .setControlLayer(cl_middleButtons) - - y = y + 1.5 - middleButtons.btn_Link = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Pan = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Channel = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Scroll = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = p_x - y = y + 1 - middleButtons.btn_Master = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Click = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Section = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - x = x + 1 - middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) - .setControlLayer(cl_middleButtons) - - middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { - if (var_Debug == true) - console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) - } - - middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_PrevTrack) - } else { - turnOffLED(context, const_PrevTrack) - } - } - - middleButtons.btn_NextTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_NextTrack) - } else { - turnOffLED(context, const_NextTrack) - } - } - - middleButtons.btn_Link.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Link) - } else { - turnOffLED(context, const_Link) - } - } - - middleButtons.btn_Click.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Click) - } else { - turnOffLED(context, const_Click) - } - } - - return middleButtons -} - -function midiBindingMiddleButtons(p_middleButtons) { - p_middleButtons.btn_PrevTrack.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_PrevTrack) - - p_middleButtons.kb_Rotary.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToControlChange(0, const_Rotary) - .setTypeRelativeSignedBit() - - p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote(0, const_RotaryPush) - - p_middleButtons.btn_NextTrack.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_NextTrack) - - p_middleButtons.btn_Link.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Link) - - p_middleButtons.btn_Pan.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Pan) - - p_middleButtons.btn_Channel.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Channel) - - p_middleButtons.btn_Scroll.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Scroll) - - p_middleButtons.btn_Master.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Master) - - p_middleButtons.btn_Click.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Click) - - p_middleButtons.btn_Section.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Section) - - p_middleButtons.btn_Marker.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Marker) -} - -function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { - p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) - p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) - - var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') - var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') - var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') - var subpage_Scroll = sba_SubPageArea.makeSubPage('Scroll') - var subpage_Master = sba_SubPageArea.makeSubPage('Master') - var subpage_Section = sba_SubPageArea.makeSubPage('Section') - var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') - - // Pan - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) - .setSubPage(subpage_Pan) - p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) - .setSubPage(subpage_Pan) - .setTypeToggle() - - // Channel - //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) - // .setSubPage(subpage_Scroll) - - // Scroll - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) - .setSubPage(subpage_Scroll) - - // Master - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) - .setSubPage(subpage_Master) - - // Section - - // Marker - - //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) - // .setSubPage(subpage_Master) - // .setTypeToggle() - - p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) - .setTypeToggle() - - p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) - - p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) - .setTypeToggle() - - p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) - - subpage_Pan.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOnLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Pan.mOnDeactivate = function(context) { - turnOffLED(context, const_Pan) - } - - subpage_Channel.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOnLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Channel.mOnDeactivate = function(context) { - turnOffLED(context, const_Channel) - } - - subpage_Scroll.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOnLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Scroll.mOnDeactivate = function(context) { - turnOffLED(context, const_Scroll) - } - - subpage_Master.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOnLED(context, const_Master) - turnOffLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Master.mOnDeactivate = function(context) { - turnOffLED(context, const_Master) - } - - subpage_Section.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOnLED(context, const_Section) - turnOffLED(context, const_Marker) - } - subpage_Section.mOnDeactivate = function(context) { - turnOffLED(context, const_Section) - } - - subpage_Marker.mOnActivate = function(context) { - turnOffLED(context, const_Link) - turnOffLED(context, const_Pan) - turnOffLED(context, const_Channel) - turnOffLED(context, const_Scroll) - turnOffLED(context, const_Master) - turnOffLED(context, const_Section) - turnOnLED(context, const_Marker) - } - subpage_Marker.mOnDeactivate = function(context) { - turnOffLED(context, const_Marker) - } -} - -/** TRANSPORT BUTTONS - * - */ - -function makeTransportButtons(p_x, p_y) { - var transportButtons = {} - var x = p_x - var y = p_y - var width = 1 - var heigh = 1 - - transportButtons.btn_Loop = deviceDriver.mSurface.makeButton(x + 0.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_RWD = deviceDriver.mSurface.makeButton(x + 1.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_FWD = deviceDriver.mSurface.makeButton(x + 2.5, y, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Stop = deviceDriver.mSurface.makeButton(x + 0.25, y + 1, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Play = deviceDriver.mSurface.makeButton(x + 1.375, y + 1.125, width * 1.25, heigh* 1.25) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Record = deviceDriver.mSurface.makeButton(x + 2.75, y + 1, width, heigh) - .setShapeCircle() - .setControlLayer(cl_TransportButtons) - - transportButtons.btn_Loop.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Loop) - } else { - turnOffLED(context, const_Loop) - } - } - - transportButtons.btn_Stop.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOnLED(context, const_Stop) - } else { - turnOffLED(context, const_Stop) - } - } - - transportButtons.btn_Play.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOffLED(context, const_Stop) - turnOnLED(context, const_Play) - } else { - turnOnLED(context, const_Stop) - turnOffLED(context, const_Play) - } - } - - transportButtons.btn_Record.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (value) { - turnOffLED(context, const_Stop) - turnOnLED(context, const_Record) - turnOnLED(context, const_Play) - } else { - turnOffLED(context, const_Record) - } - } - - transportButtons.btn_RWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (!value) { - turnOffLED(context, const_RWD) - } else { - turnOnLED(context, const_RWD) - } - } - - transportButtons.btn_FWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { - if (!value) { - turnOffLED(context, const_FWD) - } else { - turnOnLED(context, const_FWD) - } - } - - return transportButtons -} - -function midiBindingTransportButtons(p_transportButtons) { - p_transportButtons.btn_Loop.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Loop) - - p_transportButtons.btn_RWD.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_RWD) - - p_transportButtons.btn_FWD.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_FWD) - - p_transportButtons.btn_Stop.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Stop) - - p_transportButtons.btn_Play.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Play) - - p_transportButtons.btn_Record.mSurfaceValue.mMidiBinding - .setInputPort(midiInput) - .bindToNote (0, const_Record) -} - -function hostBindingTransportButtons(p_transportButtons, p_Page, pageShift) { - var transport = page.mHostAccess.mTransport.mValue - page.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport.mCycleActive) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport.mRewind) - page.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport.mForward) - page.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport.mStop) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport.mStart) - .setTypeToggle() - page.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport.mRecord) - .setTypeToggle() - - var transport_pageShift = pageShift.mHostAccess.mTransport.mValue - pageShift.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport_pageShift.mCycleActive) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport_pageShift.mRewind) - pageShift.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport_pageShift.mForward) - pageShift.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport_pageShift.mStop) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport_pageShift.mStart) - .setTypeToggle() - pageShift.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport_pageShift.mRecord) - .setTypeToggle() -} - -/** MAIN - * - */ -var page = deviceDriver.mMapping.makePage('PreSonus FP2 MAIN') -var pageShift = deviceDriver.mMapping.makePage('PreSonus FP2 SHIFT') -var var_Debug = false - -var fader = makeFader(0, 0, 9) -midiBindingFader(fader) -hostBindingFader(fader, page, pageShift) - -var upperButtons = makeUpperButtons(2, 0) -midiBindingUpperButtons(upperButtons) -hostBindingUpperButtons(upperButtons, page, pageShift) - -var middleButtons = makeMiddleButtons(2, 3) -midiBindingMiddleButtons(middleButtons) -hostBindingMiddleButtons(middleButtons, page, pageShift) - -var transportButtons = makeTransportButtons(2, 7) -midiBindingTransportButtons(transportButtons) -hostBindingTransportButtons(transportButtons, page, pageShift) From 830bce9de465489ca0c1d1abe292108fd94cb919 Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 2 May 2022 11:23:54 +0200 Subject: [PATCH 5/9] Create Presonus_FaderPort.js --- presonus/faderport/Presonus_FaderPort.js | 776 +++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 presonus/faderport/Presonus_FaderPort.js diff --git a/presonus/faderport/Presonus_FaderPort.js b/presonus/faderport/Presonus_FaderPort.js new file mode 100644 index 0000000..b94635d --- /dev/null +++ b/presonus/faderport/Presonus_FaderPort.js @@ -0,0 +1,776 @@ +//----------------------------------------------------------------------------- +// 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 Music') + +// 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 +//----------------------------------------------------------------------------- + +/** Definitions + * + */ + +const const_FaderTouch = 0x68 + +// Upper +const const_Solo = 0x08 +const const_Mute = 0x10 +const const_Arm = 0x00 +const const_Shift = 0x46 +const const_Bypass = 0x03 +const const_Touch = 0x4D +const const_Write = 0x4B +const const_Read = 0x4A + +// Middle +const const_PrevTrack = 0x2E +const const_Rotary = 0x10 +const const_RotaryPush = 0x20 +const const_NextTrack = 0x2F + +const const_Link = 0x05 +const const_Pan = 0x2A +const const_Channel = 0x36 +const const_Scroll = 0x38 +const const_Master = 0x3A +const const_Click = 0x3B +const const_Section = 0x3C +const const_Marker = 0x3D + +// Transport +const const_Loop = 0x56 +const const_RWD = 0x5B +const const_FWD = 0x5C +const const_Stop = 0x5D +const const_Play = 0x5E +const const_Record = 0x5F + +/** Help Functions + * + */ +// helpers to turn on/off the button LEDs +function turnOnLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x7F]) +} +function turnFlashingLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x01]) +} +function turnOffLED(device, ledID) +{ + midiOutput.sendMidi(device, [ 0x90, ledID, 0x00]) +} +function setRGBLED(device, ledID, r, g, b) { + midiOutput.sendMidi(device, [ 0x91, ledID, r]) + midiOutput.sendMidi(device, [ 0x92, ledID, g]) + midiOutput.sendMidi(device, [ 0x93, ledID, b]) +} + +const RGB_Colors = { + c_Red: 0x01, + c_Green: 0x02, + c_Blue: 0x03 +} + +function setColorLED(device, ledID, p_color) { + if (p_color == RGB_Colors.c_Red) { + setRGBLED(device, ledID, 0x7F, 0x00, 0x00) + } else if (p_color == RGB_Colors.c_Green) { + setRGBLED(device, ledID, 0x00, 0x7F, 0x00) + } else if (p_color == RGB_Colors.c_Blue) { + setRGBLED(device, ledID, 0x00, 0x00, 0x7F) + } +} + +/** Zones + * + */ + + +var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') +var cl_fader = clz_ZoneFader.makeControlLayer('Fader') + +var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') +var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') + +var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') +var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') + +var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') +var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') + +/** FADER + * + */ + +function makeFader(p_x, p_y, p_heigh) { + var fader = {} + // create control element representing your hardware's surface + fader.fd_Volume = deviceDriver.mSurface.makeFader(p_x, p_y, 1, p_heigh) + .setTypeVertical() + fader.fd_Volume.setControlLayer(cl_fader) + + fader.val_FaderTouched = deviceDriver.mSurface.makeCustomValueVariable('FaderTouched') + fader.val_FaderOutput = deviceDriver.mSurface.makeCustomValueVariable('FaderOutput') + + var faderState = { + isTouched: false, + value: 0, + updateHardware: function(context) { + if(!this.isTouched) + if (var_Debug == true) + console.log("updateHardware: " + this.value.toString()) + fader.val_FaderOutput.setProcessValue(context, this.value) + } + } + + fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + faderState.value = value + faderState.updateHardware(context) + }.bind({faderState}) + + fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("val_FaderTouched.mOnProcessValueChange") + faderState.isTouched = value > 0 + faderState.updateHardware(context) + }.bind({faderState}) + + return fader +} + +function midiBindingFader(p_fader) { + p_fader.fd_Volume.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToPitchBend(0) + + p_fader.val_FaderTouched.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FaderTouch) + + p_fader.val_FaderOutput.mMidiBinding + .setOutputPort(midiOutput) + .bindToPitchBend(0) +} + +function hostBindingFader(p_fader, p_Page, p_pageShift) { + p_Page.makeValueBinding(fader.fd_Volume.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume) + p_pageShift.makeValueBinding(fader.fd_Volume.mSurfaceValue, pageShift.mHostAccess.mMouseCursor.mValueUnderMouse) +} + +/** UPPER BUTTONS + * + */ + +function makeUpperButtons(p_x, p_y) { + var upperButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + upperButtons.btn_Solo = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Solo.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Mute = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Mute.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Arm = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Arm.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Shift = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Shift.setControlLayer(cl_upperButtons) + x = p_x + y = y + 1 + upperButtons.btn_Bypass = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Bypass.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Touch = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Touch.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Write = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Write.setControlLayer(cl_upperButtons) + x = x + 1 + upperButtons.btn_Read = deviceDriver.mSurface.makeButton(x, y, width, heigh) + upperButtons.btn_Read.setControlLayer(cl_upperButtons) + + upperButtons.btn_Solo.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Solo) + } else { + turnOffLED(context, const_Solo) + } + } + + upperButtons.btn_Mute.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Mute) + } else { + turnOffLED(context, const_Mute) + } + } + + upperButtons.btn_Arm.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Arm) + } else { + turnOffLED(context, const_Arm) + } + } + + upperButtons.btn_Bypass.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Bypass) + } else { + turnOffLED(context, const_Bypass) + } + } + + upperButtons.btn_Write.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Write) + setColorLED(context, const_Write, RGB_Colors.c_Red) + } else { + turnOffLED(context, const_Write) + } + } + + upperButtons.btn_Read.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Read) + setColorLED(context, const_Read, RGB_Colors.c_Green) + } else { + turnOffLED(context, const_Read) + } + } + + return upperButtons +} + +function midiBindingUpperButtons(p_upperButtons) { + p_upperButtons.btn_Solo.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Solo) + + p_upperButtons.btn_Mute.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Mute) + + p_upperButtons.btn_Arm.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Arm) + + p_upperButtons.btn_Shift.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Shift) + + p_upperButtons.btn_Bypass.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Bypass) + + p_upperButtons.btn_Touch.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Touch) + + p_upperButtons.btn_Write.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Write) + + p_upperButtons.btn_Read.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Read) +} + +function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { + var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel + page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) + .setTypeToggle() + page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) + page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) + .setTypeToggle() + page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) + .setTypeToggle() + + var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel + p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) + + p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) + .setTypeToggle() + p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) + .setTypeToggle() + + p_PageShift.mOnActivate = function(context) { + turnFlashingLED(context, const_Shift) + } + + p_Page.mOnActivate = function(context) { + turnOffLED(context, const_Shift) + } +} + +/** MIDDLE BUTTONS + * + */ +function makeMiddleButtons(p_x, p_y) { + var middleButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + middleButtons.btn_PrevTrack = deviceDriver.mSurface.makeButton(x, y + 0.25, width, heigh / 2) + .setControlLayer(cl_middleButtons) + + middleButtons.pnl_KnobPanel = deviceDriver.mSurface.makeBlindPanel(x + 1, y - 0.25, width * 2, heigh + 0.5) + + middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) + .setControlLayer(cl_middleButtons) + + middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) + .setControlLayer(cl_middleButtons) + .setShapeCircle() + + middleButtons.pnl_KnobLabel = deviceDriver.mSurface.makeLabelField(x + 1.25, y + 0.75, width * 2 - 0.5, 0.25) + .relateTo(middleButtons.kb_Rotary) + + middleButtons.btn_NextTrack = deviceDriver.mSurface.makeButton(x + 3, y + 0.25, width, heigh/2) + .setControlLayer(cl_middleButtons) + + y = y + 1.5 + middleButtons.btn_Link = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Pan = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Channel = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Scroll = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = p_x + y = y + 1 + middleButtons.btn_Master = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Click = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Section = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + x = x + 1 + middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) + .setControlLayer(cl_middleButtons) + + middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + } + + middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_PrevTrack) + } else { + turnOffLED(context, const_PrevTrack) + } + } + + middleButtons.btn_NextTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_NextTrack) + } else { + turnOffLED(context, const_NextTrack) + } + } + + middleButtons.btn_Link.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Link) + } else { + turnOffLED(context, const_Link) + } + } + + middleButtons.btn_Click.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Click) + } else { + turnOffLED(context, const_Click) + } + } + + return middleButtons +} + +function midiBindingMiddleButtons(p_middleButtons) { + p_middleButtons.btn_PrevTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_PrevTrack) + + p_middleButtons.kb_Rotary.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToControlChange(0, const_Rotary) + .setTypeRelativeSignedBit() + + p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote(0, const_RotaryPush) + + p_middleButtons.btn_NextTrack.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_NextTrack) + + p_middleButtons.btn_Link.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Link) + + p_middleButtons.btn_Pan.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Pan) + + p_middleButtons.btn_Channel.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Channel) + + p_middleButtons.btn_Scroll.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Scroll) + + p_middleButtons.btn_Master.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Master) + + p_middleButtons.btn_Click.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Click) + + p_middleButtons.btn_Section.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Section) + + p_middleButtons.btn_Marker.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Marker) +} + +function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + + var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') + var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') + var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') + var subpage_Scroll = sba_SubPageArea.makeSubPage('Scroll') + var subpage_Master = sba_SubPageArea.makeSubPage('Master') + var subpage_Section = sba_SubPageArea.makeSubPage('Section') + var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') + + // Pan + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + .setSubPage(subpage_Pan) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Pan) + .setTypeToggle() + + // Channel + //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) + // .setSubPage(subpage_Scroll) + + // Scroll + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Scroll) + + // Master + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) + .setSubPage(subpage_Master) + + // Section + + // Marker + + //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + // .setSubPage(subpage_Master) + // .setTypeToggle() + + p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) + + p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) + .setTypeToggle() + + p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) + p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) + + subpage_Pan.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOnLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Pan.mOnDeactivate = function(context) { + turnOffLED(context, const_Pan) + } + + subpage_Channel.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOnLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Channel.mOnDeactivate = function(context) { + turnOffLED(context, const_Channel) + } + + subpage_Scroll.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOnLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Scroll.mOnDeactivate = function(context) { + turnOffLED(context, const_Scroll) + } + + subpage_Master.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOnLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Master.mOnDeactivate = function(context) { + turnOffLED(context, const_Master) + } + + subpage_Section.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOnLED(context, const_Section) + turnOffLED(context, const_Marker) + } + subpage_Section.mOnDeactivate = function(context) { + turnOffLED(context, const_Section) + } + + subpage_Marker.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOnLED(context, const_Marker) + } + subpage_Marker.mOnDeactivate = function(context) { + turnOffLED(context, const_Marker) + } +} + +/** TRANSPORT BUTTONS + * + */ + +function makeTransportButtons(p_x, p_y) { + var transportButtons = {} + var x = p_x + var y = p_y + var width = 1 + var heigh = 1 + + transportButtons.btn_Loop = deviceDriver.mSurface.makeButton(x + 0.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_RWD = deviceDriver.mSurface.makeButton(x + 1.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_FWD = deviceDriver.mSurface.makeButton(x + 2.5, y, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Stop = deviceDriver.mSurface.makeButton(x + 0.25, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Play = deviceDriver.mSurface.makeButton(x + 1.375, y + 1.125, width * 1.25, heigh* 1.25) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Record = deviceDriver.mSurface.makeButton(x + 2.75, y + 1, width, heigh) + .setShapeCircle() + .setControlLayer(cl_TransportButtons) + + transportButtons.btn_Loop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Loop) + } else { + turnOffLED(context, const_Loop) + } + } + + transportButtons.btn_Stop.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOnLED(context, const_Stop) + } else { + turnOffLED(context, const_Stop) + } + } + + transportButtons.btn_Play.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Play) + } else { + turnOnLED(context, const_Stop) + turnOffLED(context, const_Play) + } + } + + transportButtons.btn_Record.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (value) { + turnOffLED(context, const_Stop) + turnOnLED(context, const_Record) + turnOnLED(context, const_Play) + } else { + turnOffLED(context, const_Record) + } + } + + transportButtons.btn_RWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_RWD) + } else { + turnOnLED(context, const_RWD) + } + } + + transportButtons.btn_FWD.mSurfaceValue.mOnProcessValueChange = function(context, value) { + if (!value) { + turnOffLED(context, const_FWD) + } else { + turnOnLED(context, const_FWD) + } + } + + return transportButtons +} + +function midiBindingTransportButtons(p_transportButtons) { + p_transportButtons.btn_Loop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Loop) + + p_transportButtons.btn_RWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_RWD) + + p_transportButtons.btn_FWD.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_FWD) + + p_transportButtons.btn_Stop.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Stop) + + p_transportButtons.btn_Play.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Play) + + p_transportButtons.btn_Record.mSurfaceValue.mMidiBinding + .setInputPort(midiInput) + .bindToNote (0, const_Record) +} + +function hostBindingTransportButtons(p_transportButtons, p_Page, pageShift) { + var transport = page.mHostAccess.mTransport.mValue + page.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport.mCycleActive) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport.mRewind) + page.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport.mForward) + page.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport.mStop) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport.mStart) + .setTypeToggle() + page.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport.mRecord) + .setTypeToggle() + + var transport_pageShift = pageShift.mHostAccess.mTransport.mValue + pageShift.makeValueBinding(p_transportButtons.btn_Loop.mSurfaceValue, transport_pageShift.mCycleActive) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_RWD.mSurfaceValue, transport_pageShift.mRewind) + pageShift.makeValueBinding(p_transportButtons.btn_FWD.mSurfaceValue, transport_pageShift.mForward) + pageShift.makeValueBinding(p_transportButtons.btn_Stop.mSurfaceValue, transport_pageShift.mStop) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Play.mSurfaceValue, transport_pageShift.mStart) + .setTypeToggle() + pageShift.makeValueBinding(p_transportButtons.btn_Record.mSurfaceValue, transport_pageShift.mRecord) + .setTypeToggle() +} + +/** MAIN + * + */ +var page = deviceDriver.mMapping.makePage('PreSonus FP2 MAIN') +var pageShift = deviceDriver.mMapping.makePage('PreSonus FP2 SHIFT') +var var_Debug = false + +var fader = makeFader(0, 0, 9) +midiBindingFader(fader) +hostBindingFader(fader, page, pageShift) + +var upperButtons = makeUpperButtons(2, 0) +midiBindingUpperButtons(upperButtons) +hostBindingUpperButtons(upperButtons, page, pageShift) + +var middleButtons = makeMiddleButtons(2, 3) +midiBindingMiddleButtons(middleButtons) +hostBindingMiddleButtons(middleButtons, page, pageShift) + +var transportButtons = makeTransportButtons(2, 7) +midiBindingTransportButtons(transportButtons) +hostBindingTransportButtons(transportButtons, page, pageShift) From 0f4c417ad44a218d8bbd67821e510288d7e60390 Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Mon, 20 Jun 2022 19:46:07 +0200 Subject: [PATCH 6/9] General update and functional extention --- presonus/faderport/Presonus_FaderPort.js | 431 ++++++++++++++++++++--- 1 file changed, 391 insertions(+), 40 deletions(-) diff --git a/presonus/faderport/Presonus_FaderPort.js b/presonus/faderport/Presonus_FaderPort.js index b94635d..a605643 100644 --- a/presonus/faderport/Presonus_FaderPort.js +++ b/presonus/faderport/Presonus_FaderPort.js @@ -24,9 +24,10 @@ deviceDriver.makeDetectionUnit().detectPortPair(midiInput, midiOutput) * */ +// Fader const const_FaderTouch = 0x68 -// Upper +// Upper Zone const const_Solo = 0x08 const const_Mute = 0x10 const const_Arm = 0x00 @@ -36,7 +37,7 @@ const const_Touch = 0x4D const const_Write = 0x4B const const_Read = 0x4A -// Middle +// Middle Zone const const_PrevTrack = 0x2E const const_Rotary = 0x10 const const_RotaryPush = 0x20 @@ -51,7 +52,7 @@ const const_Click = 0x3B const const_Section = 0x3C const const_Marker = 0x3D -// Transport +// Transport Zone const const_Loop = 0x56 const const_RWD = 0x5B const const_FWD = 0x5C @@ -59,6 +60,27 @@ const const_Stop = 0x5D const const_Play = 0x5E const const_Record = 0x5F +// Helper Variables + +// Saves the last Position of the Knob +var var_prev_Rotary = -1 + +// Pages +const Pages = { + c_Page_None: 0x01, + c_Page_Pan: 0x02, + c_Page_Channel: 0x03, + c_Page_Scroll: 0x04, + c_Page_Master: 0x05, + c_Page_Section: 0x06, + c_Page_Marker: 0x07, + c_Page_Zoom: 0x08, + c_Page_Zoom_Vertical: 0x09 +} + +var var_Active_Page = Pages.c_Page_None + + /** Help Functions * */ @@ -101,18 +123,17 @@ function setColorLED(device, ledID, p_color) { * */ - var clz_ZoneFader = deviceDriver.mSurface.makeControlLayerZone('Fader') var cl_fader = clz_ZoneFader.makeControlLayer('Fader') -var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('UpperButtons') -var cl_upperButtons = clz_UpperButtons.makeControlLayer('UpperButtons') +var clz_UpperButtons = deviceDriver.mSurface.makeControlLayerZone('Upper Buttons') +var cl_upperButtons = clz_UpperButtons.makeControlLayer('Upper Buttons') -var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('MiddleButtons') -var cl_middleButtons = clz_MiddleButtons.makeControlLayer('MiddleButtons') +var clz_MiddleButtons = deviceDriver.mSurface.makeControlLayerZone('Middle Buttons') +var cl_middleButtons = clz_MiddleButtons.makeControlLayer('Middle Buttons') -var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('TransportButtons') -var cl_TransportButtons = clz_TransportButtons.makeControlLayer('TransportButtons') +var clz_TransportButtons = deviceDriver.mSurface.makeControlLayerZone('Transport Buttons') +var cl_TransportButtons = clz_TransportButtons.makeControlLayer('Transport Buttons') /** FADER * @@ -300,20 +321,20 @@ function midiBindingUpperButtons(p_upperButtons) { function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { var mixerChannel = page.mHostAccess.mTrackSelection.mMixerChannel - page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) - .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) + p_Page.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel.mValue.mSolo) .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) + p_Page.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel.mValue.mMute) .setTypeToggle() - page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) - page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) + p_Page.makeValueBinding(p_upperButtonss.btn_Arm.mSurfaceValue, mixerChannel.mValue.mRecordEnable) .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Touch.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) + p_Page.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_PageShift.mAction.mActivate) + + p_Page.makeValueBinding(p_upperButtonss.btn_Bypass.mSurfaceValue, mixerChannel.mCueSends.mBypass) .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) + p_Page.makeCommandBinding(p_upperButtonss.btn_Touch.mSurfaceValue, 'Audio Performance', 'Reset Processing Overload Indicator') + p_Page.makeValueBinding(p_upperButtonss.btn_Write.mSurfaceValue, mixerChannel.mValue.mAutomationWrite) .setTypeToggle() - page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) + p_Page.makeValueBinding(p_upperButtonss.btn_Read.mSurfaceValue, mixerChannel.mValue.mAutomationRead) .setTypeToggle() var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel @@ -350,7 +371,26 @@ function makeMiddleButtons(p_x, p_y) { middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) .setControlLayer(cl_middleButtons) + + // Scrolling through Channels doesn't work yet + //middleButtons.kb_Rotary_Channel_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Left") + //middleButtons.kb_Rotary_Channel_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Right") + middleButtons.kb_Rotary_Scroll_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Scroll_Left") + middleButtons.kb_Rotary_Scroll_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Scroll_Right") + + middleButtons.kb_Rotary_Section_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Section_Left") + middleButtons.kb_Rotary_Section_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Section_Right") + + middleButtons.kb_Rotary_Marker_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Marker_Left") + middleButtons.kb_Rotary_Marker_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Marker_Right") + + middleButtons.kb_Rotary_Zoom_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Left") + middleButtons.kb_Rotary_Zoom_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Right") + + middleButtons.kb_Rotary_Zoom_Vertical_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Vertical_Left") + middleButtons.kb_Rotary_Zoom_Vertical_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Vertical_Right") + middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) .setControlLayer(cl_middleButtons) .setShapeCircle() @@ -390,6 +430,105 @@ function makeMiddleButtons(p_x, p_y) { middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { if (var_Debug == true) console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) + + // Evaluate if knob is turned right or left + const Direction = { + c_Direction_None: 0x00, + c_Direction_Left: 0x01, + c_Direction_Right: 0x02 + } + var var_Direction = Direction.c_Direction_None + + if (var_prev_Rotary == -1) + var_prev_Rotary = value + else { + if (var_prev_Rotary == 1 && value == 1) { + var_Direction = Direction.c_Direction_Right + } else if (var_prev_Rotary == 0 && value == 0) { + var_Direction = Direction.c_Direction_Left + } else if (var_prev_Rotary < value) { + var_Direction = Direction.c_Direction_Right + } else if (var_prev_Rotary > value) { + var_Direction = Direction.c_Direction_Left + } else { + var_Direction = Direction.c_Direction_None + } + var_prev_Rotary = value + } + + // Fill the to the page corresponding variables + switch (var_Active_Page) { + case Pages.c_Page_None: + break + case Pages.c_Page_Pan: + break + case Pages.c_Page_Channel: + // Scrolling through channels doesn't work yet + /** + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Channel_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Channel_Right.setProcessValue(context, 1) + break + } + */ + break + case Pages.c_Page_Scroll: + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Scroll_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Scroll_Right.setProcessValue(context, 1) + break + } + break + case Pages.c_Page_Master: + break + case Pages.c_Page_Section: + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Section_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Section_Right.setProcessValue(context, 1) + break + } + break + case Pages.c_Page_Marker: + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Marker_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Marker_Right.setProcessValue(context, 1) + break + } + break + case Pages.c_Page_Zoom: + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Zoom_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Zoom_Right.setProcessValue(context, 1) + break + } + break + case Pages.c_Page_Zoom_Vertical: + switch (var_Direction) { + case Direction.c_Direction_Left: + middleButtons.kb_Rotary_Zoom_Vertical_Left.setProcessValue(context, 1) + break + case Direction.c_Direction_Right: + middleButtons.kb_Rotary_Zoom_Vertical_Right.setProcessValue(context, 1) + break + } + break + } + } middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { @@ -479,9 +618,6 @@ function midiBindingMiddleButtons(p_middleButtons) { } function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { - p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) - p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) - var sba_SubPageArea = p_Page.makeSubPageArea('Knob Area') var subpage_Pan = sba_SubPageArea.makeSubPage('Pan') var subpage_Channel = sba_SubPageArea.makeSubPage('Channel') @@ -490,48 +626,134 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { var subpage_Section = sba_SubPageArea.makeSubPage('Section') var subpage_Marker = sba_SubPageArea.makeSubPage('Marker') + var sba_SubPageArea_Shift = p_PageShift.makeSubPageArea('Knob Area Shift') + var subpage_Zoom = sba_SubPageArea_Shift.makeSubPage('Zoom') + var subpage_Zoom_Vertical = sba_SubPageArea_Shift.makeSubPage('Zoom_Vertical') + + subpage_Pan.mActivate + + /********************************** + * Normal page + */ // Pan - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + .setSubPage(subpage_Pan) p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) .setSubPage(subpage_Pan) .setTypeToggle() + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + .setSubPage(subpage_Pan) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + .setSubPage(subpage_Pan) // Channel - //p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.) - // .setSubPage(subpage_Scroll) + p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) + .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Channel) + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + .setSubPage(subpage_Channel) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + .setSubPage(subpage_Channel) + // Scrolling through channels doesn't work yet + //p_Page.makeActionBinding(p_middleButtons.kb_Rotary_Channel_Left, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) + // .setSubPage(subpage_Channel) + //p_Page.makeActionBinding(p_middleButtons.kb_Rotary_Channel_Right, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + // .setSubPage(subpage_Channel) + //p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Left, 'Project', 'Select Track: Prev') + // .setSubPage(subpage_Channel) + //p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Right, 'Project', 'Select Track: Next') + // .setSubPage(subpage_Channel) // Scroll - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) + .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Transport', 'Nudge Cursor Left') + .setSubPage(subpage_Scroll) + p_Page.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Transport', 'Nudge Cursor Right') + .setSubPage(subpage_Scroll) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Scroll_Left, 'Transport', 'Nudge Cursor Left') + .setSubPage(subpage_Scroll) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Scroll_Right, 'Transport', 'Nudge Cursor Right') .setSubPage(subpage_Scroll) // Master - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mReferenceLevelValue) + p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) + .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mMainChannel.mLevelValue) .setSubPage(subpage_Master) // Section + p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) + .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Nudge', 'Left') + .setSubPage(subpage_Section) + p_Page.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Nudge', 'Right') + .setSubPage(subpage_Section) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Section_Left, 'Nudge', 'Left') + .setSubPage(subpage_Section) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Section_Right, 'Nudge', 'Right') + .setSubPage(subpage_Section) // Marker - - //p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) - // .setSubPage(subpage_Master) - // .setTypeToggle() - + p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) + .setSubPage(subpage_Pan) + .setSubPage(subpage_Channel) + .setSubPage(subpage_Scroll) + .setSubPage(subpage_Master) + .setSubPage(subpage_Section) + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Transport', 'Locate Previous Marker') + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Transport', 'Locate Next Marker') + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Marker_Left, 'Transport', 'Locate Previous Marker') + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Marker_Right, 'Transport', 'Locate Next Marker') + .setSubPage(subpage_Marker) + + // Open Channel Editor p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) .setTypeToggle() - - p_Page.makeActionBinding(p_middleButtons.btn_Pan.mSurfaceValue, subpage_Pan.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Channel.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) + // Click p_Page.makeValueBinding(p_middleButtons.btn_Click.mSurfaceValue, p_Page.mHostAccess.mTransport.mValue.mMetronomeActive) .setTypeToggle() - p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) - p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) - + // Pan Page Handler subpage_Pan.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOnLED(context, const_Pan) turnOffLED(context, const_Channel) @@ -539,12 +761,22 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Master) turnOffLED(context, const_Section) turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Pan } subpage_Pan.mOnDeactivate = function(context) { turnOffLED(context, const_Pan) + + var_Active_Page = Pages.c_Page_None } + // Channel Page Handler subpage_Channel.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOnLED(context, const_Channel) @@ -552,12 +784,22 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Master) turnOffLED(context, const_Section) turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Channel } subpage_Channel.mOnDeactivate = function(context) { turnOffLED(context, const_Channel) + + var_Active_Page = Pages.c_Page_None } + // Scroll Page Handler subpage_Scroll.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOffLED(context, const_Channel) @@ -565,12 +807,22 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Master) turnOffLED(context, const_Section) turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Scroll } subpage_Scroll.mOnDeactivate = function(context) { turnOffLED(context, const_Scroll) + + var_Active_Page = Pages.c_Page_None } + // Master Page Handler subpage_Master.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOffLED(context, const_Channel) @@ -578,12 +830,22 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOnLED(context, const_Master) turnOffLED(context, const_Section) turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Master } subpage_Master.mOnDeactivate = function(context) { turnOffLED(context, const_Master) + + var_Active_Page = Pages.c_Page_None } + // Section Page Handler subpage_Section.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOffLED(context, const_Channel) @@ -591,12 +853,22 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Master) turnOnLED(context, const_Section) turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Section } subpage_Section.mOnDeactivate = function(context) { turnOffLED(context, const_Section) + + var_Active_Page = Pages.c_Page_None } + // Marker Page Handler subpage_Marker.mOnActivate = function(context) { + setColorLED(context, const_Link, RGB_Colors.c_Blue) + setColorLED(context, const_Pan, RGB_Colors.c_Blue) + setColorLED(context, const_Channel, RGB_Colors.c_Blue) + setColorLED(context, const_Scroll, RGB_Colors.c_Blue) + turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOffLED(context, const_Channel) @@ -604,10 +876,89 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Master) turnOffLED(context, const_Section) turnOnLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Marker } subpage_Marker.mOnDeactivate = function(context) { turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_None } + + /********************************** + * Shift page + */ + var mixerChannel = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel + p_PageShift.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, mixerChannel.mValue.mInstrumentOpen) + .setTypeToggle() + + // Zoom Button + p_PageShift.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Zoom.mAction.mActivate) + .setSubPage(subpage_Zoom) + .setSubPage(subpage_Zoom_Vertical) + p_PageShift.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Zoom', 'Zoom Out') + .setSubPage(subpage_Zoom) + p_PageShift.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Zoom', 'Zoom In') + .setSubPage(subpage_Zoom) + p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Left, 'Zoom', 'Zoom Out') + .setSubPage(subpage_Zoom) + p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Right, 'Zoom', 'Zoom In') + .setSubPage(subpage_Zoom) + + // Zoom Button + p_PageShift.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Zoom_Vertical.mAction.mActivate) + .setSubPage(subpage_Zoom) + .setSubPage(subpage_Zoom_Vertical) + p_PageShift.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Zoom', 'Zoom Out Vertically') + .setSubPage(subpage_Zoom_Vertical) + p_PageShift.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Zoom', 'Zoom In Vertically') + .setSubPage(subpage_Zoom_Vertical) + p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Vertical_Left, 'Zoom', 'Zoom Out Vertically') + .setSubPage(subpage_Zoom_Vertical) + p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Vertical_Right, 'Zoom', 'Zoom In Vertically') + .setSubPage(subpage_Zoom_Vertical) + + // F1 to F4 + p_PageShift.makeCommandBinding(p_middleButtons.btn_Master.mSurfaceValue, 'Quantize Category', 'Set Quantize to 2th') + p_PageShift.makeCommandBinding(p_middleButtons.btn_Click.mSurfaceValue, 'Quantize Category', 'Set Quantize to 4th') + p_PageShift.makeCommandBinding(p_middleButtons.btn_Section.mSurfaceValue, 'Quantize Category', 'Set Quantize to 8th') + p_PageShift.makeCommandBinding(p_middleButtons.btn_Marker.mSurfaceValue, 'Quantize Category', 'Set Quantize to 16th') + + // Zoom Page Handler + subpage_Zoom.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOffLED(context, const_Channel) + turnOnLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Zoom + } + subpage_Zoom.mOnDeactivate = function(context) { + turnOnLED(context, const_Scroll) + + var_Active_Page = Pages.c_Page_None + } + + // Zoom Vertical Page Handler + subpage_Zoom_Vertical.mOnActivate = function(context) { + turnOffLED(context, const_Link) + turnOffLED(context, const_Pan) + turnOnLED(context, const_Channel) + turnOffLED(context, const_Scroll) + turnOffLED(context, const_Master) + turnOffLED(context, const_Section) + turnOffLED(context, const_Marker) + + var_Active_Page = Pages.c_Page_Zoom_Vertical + } + subpage_Zoom_Vertical.mOnDeactivate = function(context) { + turnOnLED(context, const_Scroll) + + var_Active_Page = Pages.c_Page_None + } } /** TRANSPORT BUTTONS From bfdf553a869cbd5fa5445eb74fdbd7cf689e1d46 Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Sat, 13 Aug 2022 14:43:25 +0200 Subject: [PATCH 7/9] Update Presonus_FaderPort.js --- presonus/faderport/Presonus_FaderPort.js | 201 +++++++++++++++-------- 1 file changed, 134 insertions(+), 67 deletions(-) diff --git a/presonus/faderport/Presonus_FaderPort.js b/presonus/faderport/Presonus_FaderPort.js index a605643..e3016c2 100644 --- a/presonus/faderport/Presonus_FaderPort.js +++ b/presonus/faderport/Presonus_FaderPort.js @@ -75,7 +75,7 @@ const Pages = { c_Page_Section: 0x06, c_Page_Marker: 0x07, c_Page_Zoom: 0x08, - c_Page_Zoom_Vertical: 0x09 + c_Page_Lock: 0x09 } var var_Active_Page = Pages.c_Page_None @@ -153,6 +153,9 @@ function makeFader(p_x, p_y, p_heigh) { isTouched: false, value: 0, updateHardware: function(context) { + // skip if knob controls value under mouse + if (var_Active_Page == Pages.c_Page_Lock) + return if(!this.isTouched) if (var_Debug == true) console.log("updateHardware: " + this.value.toString()) @@ -161,6 +164,9 @@ function makeFader(p_x, p_y, p_heigh) { } fader.fd_Volume.mSurfaceValue.mOnProcessValueChange = function (context, value) { + // skip if knob controls value under mouse + if (var_Active_Page == Pages.c_Page_Lock) + return if (var_Debug == true) console.log("fd_Volume.mSurfaceValue.mOnProcessValueChange: " + value.toString()) faderState.value = value @@ -168,6 +174,9 @@ function makeFader(p_x, p_y, p_heigh) { }.bind({faderState}) fader.val_FaderTouched.mOnProcessValueChange = function (context, value) { + // skip if knob controls value under mouse + if (var_Active_Page == Pages.c_Page_Lock) + return if (var_Debug == true) console.log("val_FaderTouched.mOnProcessValueChange") faderState.isTouched = value > 0 @@ -340,13 +349,15 @@ function hostBindingUpperButtons(p_upperButtonss, p_Page, p_PageShift) { var mixerChannel_pageShift = p_PageShift.mHostAccess.mTrackSelection.mMixerChannel p_PageShift.makeActionBinding(p_upperButtonss.btn_Shift.mSurfaceValue, p_Page.mAction.mActivate) - p_PageShift.makeValueBinding(p_upperButtonss.btn_Solo.mSurfaceValue, mixerChannel_pageShift.mValue.mSolo) - .setTypeToggle() - p_PageShift.makeValueBinding(p_upperButtonss.btn_Mute.mSurfaceValue, mixerChannel_pageShift.mValue.mMute) - .setTypeToggle() + p_PageShift.makeCommandBinding(p_upperButtonss.btn_Solo.mSurfaceValue, 'Edit', 'Deactivate All Solo') + p_PageShift.makeCommandBinding(p_upperButtonss.btn_Mute.mSurfaceValue, 'Edit', 'Unmute All') + p_PageShift.makeCommandBinding(p_upperButtonss.btn_Arm.mSurfaceValue, 'Mixer', 'Arm All Audio Tracks') p_PageShift.mOnActivate = function(context) { turnFlashingLED(context, const_Shift) + turnOffLED(context, const_Solo) + turnOffLED(context, const_Mute) + turnOffLED(context, const_Arm) } p_Page.mOnActivate = function(context) { @@ -371,11 +382,11 @@ function makeMiddleButtons(p_x, p_y) { middleButtons.kb_Rotary = deviceDriver.mSurface.makeKnob(x + 1 + 0.25, y, width - 0.2, heigh - 0.2) .setControlLayer(cl_middleButtons) + middleButtons.kb_Rotary_Val = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Val") - // Scrolling through Channels doesn't work yet - //middleButtons.kb_Rotary_Channel_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Left") - //middleButtons.kb_Rotary_Channel_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Right") - + middleButtons.kb_Rotary_Channel_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Left") + middleButtons.kb_Rotary_Channel_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Channel_Right") + middleButtons.kb_Rotary_Scroll_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Scroll_Left") middleButtons.kb_Rotary_Scroll_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Scroll_Right") @@ -388,9 +399,10 @@ function makeMiddleButtons(p_x, p_y) { middleButtons.kb_Rotary_Zoom_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Left") middleButtons.kb_Rotary_Zoom_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Right") - middleButtons.kb_Rotary_Zoom_Vertical_Left = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Vertical_Left") - middleButtons.kb_Rotary_Zoom_Vertical_Right = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Zoom_Vertical_Right") - + middleButtons.kb_Rotary_Pan = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_Pan") + middleButtons.kb_Rotary_ValueUnderMouse = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_ValueUnderMouse") + middleButtons.kb_Rotary_CRLevelValue = deviceDriver.mSurface.makeCustomValueVariable("kb_Rotary_CRLevelValue") + middleButtons.btn_RotaryPush = deviceDriver.mSurface.makeButton(x + 2.25, y, width - 0.5, heigh - 0.5) .setControlLayer(cl_middleButtons) .setShapeCircle() @@ -427,10 +439,40 @@ function makeMiddleButtons(p_x, p_y) { middleButtons.btn_Marker = deviceDriver.mSurface.makeButton(x, y, width, heigh) .setControlLayer(cl_middleButtons) - middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { + // Update Hardware.... + middleButtons.kb_Rotary_Pan.mOnProcessValueChange = function(context, value) { + if (var_Debug == true) { + console.log("middleButtons.kb_Rotary_Pan.mOnProcessValueChange: " + value) + } + if (var_Active_Page == Pages.c_Page_Pan) { + middleButtons.kb_Rotary_Val.setProcessValue(context, value) + } + } + + // Update Hardware.... + middleButtons.kb_Rotary_ValueUnderMouse.mOnProcessValueChange = function(context, value) { + if (var_Debug == true) { + console.log("middleButtons.kb_Rotary_ValueUnderMouse.mOnProcessValueChange: " + value) + } + if (var_Active_Page == Pages.c_Page_Lock) { + middleButtons.kb_Rotary_Val.setProcessValue(context, value) + } + } + + // Update Hardware.... + middleButtons.kb_Rotary_CRLevelValue.mOnProcessValueChange = function(context, value) { + if (var_Debug == true) { + console.log("middleButtons.kb_Rotary_CRLevelValue.mOnProcessValueChange: " + value) + } + if (var_Active_Page == Pages.c_Page_Master) { + middleButtons.kb_Rotary_Val.setProcessValue(context, value) + } + } + + middleButtons.kb_Rotary_Val.mOnProcessValueChange = function (context, value) { if (var_Debug == true) - console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) - + console.log("middleButtons.kb_Rotary_Val.mOnProcessValueChange: " + value.toString()) + // Evaluate if knob is turned right or left const Direction = { c_Direction_None: 0x00, @@ -461,10 +503,17 @@ function makeMiddleButtons(p_x, p_y) { case Pages.c_Page_None: break case Pages.c_Page_Pan: + if (var_Debug == true) { + console.log("middleButtons.kb_Rotary_Pan: " + middleButtons.kb_Rotary_Pan.getProcessValue(context)) + console.log("middleButtons.kb_Rotary_Val: " + middleButtons.kb_Rotary_Val.getProcessValue(context)) + var var_test = Math.abs(middleButtons.kb_Rotary_Pan.getProcessValue(context) - middleButtons.kb_Rotary_Val.getProcessValue(context)) + console.log("Difference: " + var_test) + } + if (Math.abs(middleButtons.kb_Rotary_Pan.getProcessValue(context) - middleButtons.kb_Rotary_Val.getProcessValue(context)) > 0.001) { + middleButtons.kb_Rotary_Pan.setProcessValue(context, value) + } break case Pages.c_Page_Channel: - // Scrolling through channels doesn't work yet - /** switch (var_Direction) { case Direction.c_Direction_Left: middleButtons.kb_Rotary_Channel_Left.setProcessValue(context, 1) @@ -472,8 +521,7 @@ function makeMiddleButtons(p_x, p_y) { case Direction.c_Direction_Right: middleButtons.kb_Rotary_Channel_Right.setProcessValue(context, 1) break - } - */ + } break case Pages.c_Page_Scroll: switch (var_Direction) { @@ -486,6 +534,9 @@ function makeMiddleButtons(p_x, p_y) { } break case Pages.c_Page_Master: + if (Math.abs(middleButtons.kb_Rotary_CRLevelValue.getProcessValue(context) - middleButtons.kb_Rotary_Val.getProcessValue(context)) > 0.001) { + middleButtons.kb_Rotary_CRLevelValue.setProcessValue(context, value) + } break case Pages.c_Page_Section: switch (var_Direction) { @@ -517,18 +568,23 @@ function makeMiddleButtons(p_x, p_y) { break } break - case Pages.c_Page_Zoom_Vertical: - switch (var_Direction) { - case Direction.c_Direction_Left: - middleButtons.kb_Rotary_Zoom_Vertical_Left.setProcessValue(context, 1) - break - case Direction.c_Direction_Right: - middleButtons.kb_Rotary_Zoom_Vertical_Right.setProcessValue(context, 1) - break - } + case Pages.c_Page_Lock: + if (var_Debug == true) { + console.log("middleButtons.kb_Rotary_ValueUnderMouse: " + middleButtons.kb_Rotary_ValueUnderMouse.getProcessValue(context)) + console.log("middleButtons.kb_Rotary_Val: " + middleButtons.kb_Rotary_Val.getProcessValue(context)) + var var_test = Math.abs(middleButtons.kb_Rotary_ValueUnderMouse.getProcessValue(context) - middleButtons.kb_Rotary_Val.getProcessValue(context)) + console.log("Difference: " + var_test) + } + if (Math.abs(middleButtons.kb_Rotary_ValueUnderMouse.getProcessValue(context) - middleButtons.kb_Rotary_Val.getProcessValue(context)) > 0.001) { + middleButtons.kb_Rotary_ValueUnderMouse.setProcessValue(context, value) + } break } + } + middleButtons.kb_Rotary.mSurfaceValue.mOnProcessValueChange = function (context, value) { + if (var_Debug == true) + console.log("kb_Rotary.mSurfaceValue.mOnProcessValueChange: " + value.toString()) } middleButtons.btn_PrevTrack.mSurfaceValue.mOnProcessValueChange = function(context, value) { @@ -576,6 +632,11 @@ function midiBindingMiddleButtons(p_middleButtons) { .bindToControlChange(0, const_Rotary) .setTypeRelativeSignedBit() + middleButtons.kb_Rotary_Val.mMidiBinding + .setInputPort(midiInput) + .bindToControlChange(0, const_Rotary) + .setTypeRelativeSignedBit() + p_middleButtons.btn_RotaryPush.mSurfaceValue.mMidiBinding .setInputPort(midiInput) .bindToNote(0, const_RotaryPush) @@ -628,7 +689,7 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { var sba_SubPageArea_Shift = p_PageShift.makeSubPageArea('Knob Area Shift') var subpage_Zoom = sba_SubPageArea_Shift.makeSubPage('Zoom') - var subpage_Zoom_Vertical = sba_SubPageArea_Shift.makeSubPage('Zoom_Vertical') + var subpage_Lock = sba_SubPageArea_Shift.makeSubPage('Lock') subpage_Pan.mActivate @@ -643,8 +704,8 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Master) .setSubPage(subpage_Section) .setSubPage(subpage_Marker) - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) - .setSubPage(subpage_Pan) + p_Page.makeValueBinding(p_middleButtons.kb_Rotary_Pan, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mPan) + .setSubPage(subpage_Pan) p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) .setSubPage(subpage_Pan) .setTypeToggle() @@ -660,22 +721,18 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Scroll) .setSubPage(subpage_Master) .setSubPage(subpage_Section) - .setSubPage(subpage_Marker) - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Left, 'Project', 'Select Track: Prev') + .setSubPage(subpage_Channel) + p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Right, 'Project', 'Select Track: Next') .setSubPage(subpage_Channel) p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) .setSubPage(subpage_Channel) p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) .setSubPage(subpage_Channel) - // Scrolling through channels doesn't work yet - //p_Page.makeActionBinding(p_middleButtons.kb_Rotary_Channel_Left, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) - // .setSubPage(subpage_Channel) - //p_Page.makeActionBinding(p_middleButtons.kb_Rotary_Channel_Right, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) - // .setSubPage(subpage_Channel) - //p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Left, 'Project', 'Select Track: Prev') - // .setSubPage(subpage_Channel) - //p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Channel_Right, 'Project', 'Select Track: Next') - // .setSubPage(subpage_Channel) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Channel) + .setTypeToggle() // Scroll p_Page.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Scroll.mAction.mActivate) @@ -684,7 +741,7 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Scroll) .setSubPage(subpage_Master) .setSubPage(subpage_Section) - .setSubPage(subpage_Marker) + .setSubPage(subpage_Marker) p_Page.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Transport', 'Nudge Cursor Left') .setSubPage(subpage_Scroll) p_Page.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Transport', 'Nudge Cursor Right') @@ -693,6 +750,9 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Scroll) p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Scroll_Right, 'Transport', 'Nudge Cursor Right') .setSubPage(subpage_Scroll) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Scroll) + .setTypeToggle() // Master p_Page.makeActionBinding(p_middleButtons.btn_Master.mSurfaceValue, subpage_Master.mAction.mActivate) @@ -701,9 +761,16 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Scroll) .setSubPage(subpage_Master) .setSubPage(subpage_Section) - .setSubPage(subpage_Marker) - p_Page.makeValueBinding(p_middleButtons.kb_Rotary.mSurfaceValue, p_Page.mHostAccess.mControlRoom.mMainChannel.mLevelValue) + .setSubPage(subpage_Marker) + p_Page.makeValueBinding(middleButtons.kb_Rotary_CRLevelValue, p_Page.mHostAccess.mControlRoom.mMainChannel.mLevelValue) + .setSubPage(subpage_Master) + p_Page.makeActionBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mPrevTrack) .setSubPage(subpage_Master) + p_Page.makeActionBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mAction.mNextTrack) + .setSubPage(subpage_Master) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Master) + .setTypeToggle() // Section p_Page.makeActionBinding(p_middleButtons.btn_Section.mSurfaceValue, subpage_Section.mAction.mActivate) @@ -721,6 +788,9 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Section) p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Section_Right, 'Nudge', 'Right') .setSubPage(subpage_Section) + p_Page.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMonitorEnable) + .setSubPage(subpage_Section) + .setTypeToggle() // Marker p_Page.makeActionBinding(p_middleButtons.btn_Marker.mSurfaceValue, subpage_Marker.mAction.mActivate) @@ -738,6 +808,8 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { .setSubPage(subpage_Marker) p_Page.makeCommandBinding(p_middleButtons.kb_Rotary_Marker_Right, 'Transport', 'Locate Next Marker') .setSubPage(subpage_Marker) + p_Page.makeCommandBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, 'Transport', 'Insert Marker') + .setSubPage(subpage_Marker) // Open Channel Editor p_Page.makeValueBinding(p_middleButtons.btn_Link.mSurfaceValue, p_Page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mEditorOpen) @@ -895,28 +967,23 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { // Zoom Button p_PageShift.makeActionBinding(p_middleButtons.btn_Scroll.mSurfaceValue, subpage_Zoom.mAction.mActivate) .setSubPage(subpage_Zoom) - .setSubPage(subpage_Zoom_Vertical) - p_PageShift.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Zoom', 'Zoom Out') + p_PageShift.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Zoom', 'Zoom Out Vertically') .setSubPage(subpage_Zoom) - p_PageShift.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Zoom', 'Zoom In') + p_PageShift.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Zoom', 'Zoom In Vertically') .setSubPage(subpage_Zoom) p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Left, 'Zoom', 'Zoom Out') .setSubPage(subpage_Zoom) p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Right, 'Zoom', 'Zoom In') .setSubPage(subpage_Zoom) - // Zoom Button - p_PageShift.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Zoom_Vertical.mAction.mActivate) - .setSubPage(subpage_Zoom) - .setSubPage(subpage_Zoom_Vertical) - p_PageShift.makeCommandBinding(p_middleButtons.btn_PrevTrack.mSurfaceValue, 'Zoom', 'Zoom Out Vertically') - .setSubPage(subpage_Zoom_Vertical) - p_PageShift.makeCommandBinding(p_middleButtons.btn_NextTrack.mSurfaceValue, 'Zoom', 'Zoom In Vertically') - .setSubPage(subpage_Zoom_Vertical) - p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Vertical_Left, 'Zoom', 'Zoom Out Vertically') - .setSubPage(subpage_Zoom_Vertical) - p_PageShift.makeCommandBinding(p_middleButtons.kb_Rotary_Zoom_Vertical_Right, 'Zoom', 'Zoom In Vertically') - .setSubPage(subpage_Zoom_Vertical) + // Lock Buton + p_PageShift.makeActionBinding(p_middleButtons.btn_Channel.mSurfaceValue, subpage_Lock.mAction.mActivate) + .setSubPage(subpage_Lock) + p_PageShift.makeValueBinding(p_middleButtons.btn_RotaryPush.mSurfaceValue, p_PageShift.mHostAccess.mMouseCursor.mValueLocked) + .setSubPage(subpage_Lock) + .setTypeToggle() + p_PageShift.makeValueBinding(p_middleButtons.kb_Rotary_ValueUnderMouse, p_PageShift.mHostAccess.mMouseCursor.mValueUnderMouse) + .setSubPage(subpage_Lock) // F1 to F4 p_PageShift.makeCommandBinding(p_middleButtons.btn_Master.mSurfaceValue, 'Quantize Category', 'Set Quantize to 2th') @@ -937,13 +1004,13 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { var_Active_Page = Pages.c_Page_Zoom } subpage_Zoom.mOnDeactivate = function(context) { - turnOnLED(context, const_Scroll) + turnOffLED(context, const_Scroll) var_Active_Page = Pages.c_Page_None } - // Zoom Vertical Page Handler - subpage_Zoom_Vertical.mOnActivate = function(context) { + // Lock Page Handler + subpage_Lock.mOnActivate = function(context) { turnOffLED(context, const_Link) turnOffLED(context, const_Pan) turnOnLED(context, const_Channel) @@ -952,13 +1019,13 @@ function hostBindingMiddleButtons(p_middleButtons, p_Page, p_PageShift) { turnOffLED(context, const_Section) turnOffLED(context, const_Marker) - var_Active_Page = Pages.c_Page_Zoom_Vertical + var_Active_Page = Pages.c_Page_Lock } - subpage_Zoom_Vertical.mOnDeactivate = function(context) { - turnOnLED(context, const_Scroll) + subpage_Lock.mOnDeactivate = function(context) { + turnOffLED(context, const_Channel) var_Active_Page = Pages.c_Page_None - } + } } /** TRANSPORT BUTTONS From 62ebca44d4aeb6034b1ac83b9c1edc0f4a408e93 Mon Sep 17 00:00:00 2001 From: WEMtify <104760257+WEMtify@users.noreply.github.com> Date: Sat, 13 Aug 2022 14:44:27 +0200 Subject: [PATCH 8/9] Add files via upload --- ...aderPort v2 - MIDI Remote Device Manual.pdf | Bin 0 -> 335905 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 presonus/faderport/PreSonus FaderPort v2 - MIDI Remote Device Manual.pdf diff --git a/presonus/faderport/PreSonus FaderPort v2 - MIDI Remote Device Manual.pdf b/presonus/faderport/PreSonus FaderPort v2 - MIDI Remote Device Manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f5c531255869eaeb684a533b4eae7379e227debb GIT binary patch literal 335905 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