From 3e8c5b4ecaddfd00fcedf67be895d54ff83b452e Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Aug 2021 14:20:45 -0500 Subject: [PATCH] A&H Xone K2: rewrite using ES6 classes with Components 0.1 --- .../Allen and Heath Xone K2.midi.xml | 3 +- .../Allen-and-Heath-Xone-K2-scripts.js | 1127 ++++++++--------- 2 files changed, 551 insertions(+), 579 deletions(-) diff --git a/res/controllers/Allen and Heath Xone K2.midi.xml b/res/controllers/Allen and Heath Xone K2.midi.xml index 38769d0ac30..03d7e0ac531 100644 --- a/res/controllers/Allen and Heath Xone K2.midi.xml +++ b/res/controllers/Allen and Heath Xone K2.midi.xml @@ -20,8 +20,7 @@ If you are using K2s, they must have Latching Layers turned off, which is the de - - + diff --git a/res/controllers/Allen-and-Heath-Xone-K2-scripts.js b/res/controllers/Allen-and-Heath-Xone-K2-scripts.js index 10fe639107b..db30f4a0a2a 100644 --- a/res/controllers/Allen-and-Heath-Xone-K2-scripts.js +++ b/res/controllers/Allen-and-Heath-Xone-K2-scripts.js @@ -257,374 +257,345 @@ XoneK2.setColumnMidi = function (columnObject, columnNumber, midiChannel) { XoneK2.setBottomButtonsMidi(columnObject.bottomButtons, columnNumber, midiChannel); }; -XoneK2.Deck = function (column, deckNumber, midiChannel) { - var theDeck = this; +XoneK2.Deck = class extends components.Deck { + constructor(column, deckNumber, midiChannel) { + super([deckNumber]); + var theDeck = this; - this.deckString = '[Channel' + deckNumber + ']'; + this.deckString = '[Channel' + deckNumber + ']'; - this.encoder = new components.Encoder({ - unshift: function () { - this.input = function (channel, control, value, status) { - direction = (value === 1) ? 1 : -1; - engine.setValue(this.group, "jog", direction * 3); - }; - }, - shift: function () { - this.input = function (channel, control, value, status) { - direction = (value === 1) ? 1 : -1; - var gain = engine.getValue(this.group, "pregain"); - engine.setValue(this.group, "pregain", gain + 0.025 * direction); - }; - }, - supershift: function () { - this.input = function (channel, control, value, status) { - direction = (value === 1) ? 1 : -1; - engine.setValue('[QuickEffectRack1_' + theDeck.deckString + ']', 'chain_selector', direction); - }; - }, - }); - - this.encoderPress = new components.Button({ - outKey: 'sync_enabled', - unshift: function () { - this.group = theDeck.deckString; - this.inKey = 'sync_enabled'; - this.type = components.Button.prototype.types.toggle; - }, - shift: function () { - this.group = '[QuickEffectRack1_' + theDeck.deckString + ']'; - this.inKey = 'enabled'; - this.type = components.Button.prototype.types.toggle; - }, - supershift: function () { - this.group = theDeck.deckString; - this.inKey = 'rate_set_zero'; - this.type = components.Button.prototype.types.push; - }, - }); - - this.knobs = new components.ComponentContainer(); - for (var k = 1; k <= 2; k++) { - this.knobs[k] = new components.Pot({ - group: '[EqualizerRack1_' + this.deckString + '_Effect1]', - inKey: 'parameter' + (4-k), + this.encoder = new components.Encoder({ + unshift: function () { + this.input = function (channel, control, value, status) { + direction = (value === 1) ? 1 : -1; + var gain = engine.getValue(this.group, "pregain"); + engine.setValue(this.group, "pregain", gain + 0.025 * direction); + }; + }, + shift: function () { + this.input = function (channel, control, value, status) { + direction = (value === 1) ? 1 : -1; + engine.setValue(this.group, "jog", direction); + }; + }, + supershift: function () { + this.input = function (channel, control, value, status) { + direction = (value === 1) ? 1 : -1; + var pitch = engine.getValue(this.group, "pitch"); + engine.setValue(this.group, "pitch", pitch + (.05 * direction)); + }; + }, }); - } - // Low EQ knob. With shift, switches to QuickEffect superknob. Stays as - // QuickEffect superknob until shift is pressed again to allow using the - // QuickEffect superknob without having to keep shift held down. This - // allows using the QuickEffect superknob for a transition while using - // the other hand for another control. - this.knobs[3] = new components.Pot({ - hasBeenTurnedSinceShiftToggle: false, - input: function (channel, control, value, status) { - components.Pot.prototype.input.call(this, channel, control, value, status); - this.hasBeenTurnedSinceShiftToggle = true; - }, - unshift: function() { - if (!this.hasBeenTurnedSinceShiftToggle) { + + this.encoderPress = new components.Button({ + outKey: 'sync_enabled', + unshift: function () { + this.inKey = 'pregain_set_one'; + this.type = components.Button.prototype.types.push; + }, + shift: function () { + this.inKey = 'sync_enabled'; + this.type = components.Button.prototype.types.toggle; + }, + supershift: function () { + this.inKey = 'reset_key'; + this.type = components.Button.prototype.types.push; + }, + }); + + this.knobs = new components.ComponentContainer(); + for (var k = 1; k <= 3; k++) { + this.knobs[k] = new components.Pot({ + group: '[EqualizerRack1_' + this.deckString + '_Effect1]', + inKey: 'parameter' + (4-k), + }); + } + + this.fader = new components.Pot({inKey: 'volume'}); + + this.topButtons = new components.ComponentContainer(); + this.topButtons[1] = new components.Button({ + unshift: function () { this.disconnect(); - this.group = '[EqualizerRack1_' + theDeck.deckString + '_Effect1]'; - this.inKey = 'parameter1'; + this.type = components.Button.prototype.types.toggle; + this.inKey = 'pfl'; + this.outKey = 'pfl'; + this.color = XoneK2.color.red; this.connect(); - } - this.hasBeenTurnedSinceShiftToggle = false; - }, - shift: function() { - this.disconnect(); - this.group = '[QuickEffectRack1_' + theDeck.deckString + ']'; - this.inKey = 'super1'; - this.connect(); - this.hasBeenTurnedSinceShiftToggle = false; - } - }); - - this.fader = new components.Pot({inKey: 'volume'}); - - this.topButtons = new components.ComponentContainer(); - this.topButtons[1] = new components.Button({ - unshift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.toggle; - this.inKey = 'pfl'; - this.outKey = 'pfl'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - shift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.push; - this.inKey = 'rate_set_zero'; - this.outKey = 'pfl'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - supershift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.push; - this.inKey = 'beats_translate_curpos'; - this.outKey = 'beats_translate_curpos'; - this.color = XoneK2.color.amber; - this.connect(); - this.trigger(); - }, - }); - this.topButtons[2] = new components.Button({ - unshift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.push; - this.inKey = 'cue_default'; - this.outKey = 'cue_indicator'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - shift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.push; - this.inKey = 'start_stop'; - this.outKey = 'cue_indicator'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - supershift: function () { - this.disconnect(); - this.type = components.Button.prototype.types.toggle; - this.inKey = 'keylock'; - this.outKey = 'keylock'; - this.color = XoneK2.color.amber; - this.connect(); - this.trigger(); - }, - }); - this.topButtons[3] = new components.Button({ - unshift: function () { - this.disconnect(); - this.inKey = 'play'; - this.outKey = 'play_indicator'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - shift: function () { - this.disconnect(); - this.inKey = 'reverse'; - this.outKey = 'play_indicator'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - supershift: function () { - this.disconnect(); - this.inKey = 'quantize'; - this.outKey = 'quantize'; - this.color = XoneK2.color.amber; - this.connect(); - this.trigger(); - }, - startDeckPickMode: function () { - this.input = function (channel, control, value, status) { - if (this.isPress(channel, control, value, status)) { - engine.setValue(this.group, "LoadSelectedTrack", 1); - XoneK2.controllers[channel].deckPicked = true; + this.trigger(); + }, + shift: function () { + this.disconnect(); + this.type = components.Button.prototype.types.push; + this.inKey = 'rate_set_zero'; + this.outKey = 'pfl'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + supershift: function () { + this.disconnect(); + this.type = components.Button.prototype.types.push; + this.inKey = 'beats_translate_curpos'; + this.outKey = 'beats_translate_curpos'; + this.color = XoneK2.color.amber; + this.connect(); + this.trigger(); + }, + }); + this.topButtons[2] = new components.Button({ + unshift: function () { + this.disconnect(); + this.type = components.Button.prototype.types.push; + this.inKey = 'cue_default'; + this.outKey = 'cue_indicator'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + shift: function () { + this.disconnect(); + this.type = components.Button.prototype.types.push; + this.inKey = 'start_stop'; + this.outKey = 'cue_indicator'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + supershift: function () { + this.disconnect(); + this.type = components.Button.prototype.types.toggle; + this.inKey = 'keylock'; + this.outKey = 'keylock'; + this.color = XoneK2.color.amber; + this.connect(); + this.trigger(); + }, + }); + this.topButtons[3] = new components.Button({ + unshift: function () { + this.disconnect(); + this.inKey = 'play'; + this.outKey = 'play_indicator'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + shift: function () { + this.disconnect(); + this.inKey = 'reverse'; + this.outKey = 'play_indicator'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + supershift: function () { + this.disconnect(); + this.inKey = 'quantize'; + this.outKey = 'quantize'; + this.color = XoneK2.color.amber; + this.connect(); + this.trigger(); + }, + startDeckPickMode: function () { + this.input = function (channel, control, value, status) { + if (this.isPress(channel, control, value, status)) { + engine.setValue(this.group, "LoadSelectedTrack", 1); + XoneK2.controllers[channel].deckPicked = true; + } + }; + }, + stopDeckPickMode: function () { + // The inKey and outKey are still set from before startDeckPickMode was + // called, so all that is needed to get back to that mode is to fall back + // to the prototype input function. + this.input = components.Button.prototype.input; + }, + type: components.Button.prototype.types.toggle, + }); + + // This should not be a ComponentContainer, otherwise strange things will + // happen when iterating over the Deck with reconnectComponents. + this.bottomButtonLayers = []; + + var CueAndSeekButton = class extends components.Button { + constructor(options) { + if (options.cueName === undefined) { + print('ERROR! cueName not specified'); + } else if (options.seekRate === undefined) { + print('ERROR! seekRate not specified'); } - }; - }, - stopDeckPickMode: function () { - // The inKey and outKey are still set from before startDeckPickMode was - // called, so all that is needed to get back to that mode is to fall back - // to the prototype input function. - this.input = components.Button.prototype.input; - }, - type: components.Button.prototype.types.toggle, - }); - - // This should not be a ComponentContainer, otherwise strange things will - // happen when iterating over the Deck with reconnectComponents. - this.bottomButtonLayers = []; - - var CueAndSeekButton = function (options) { - if (options.cueName === undefined) { - print('ERROR! cueName not specified'); - } else if (options.seekRate === undefined) { - print('ERROR! seekRate not specified'); - } - this.outKey = options.cueName + '_enabled'; - components.Button.call(this, options); - }; - CueAndSeekButton.prototype = new components.Button({ - unshift: function () { - this.inKey = this.cueName + '_activate'; - this.input = components.Button.prototype.input; - // Avoid log spam on startup - if (this.group !== undefined) { - engine.setValue(this.group, 'rateSearch', 0); + options.outKey = options.cueName + '_enabled'; + super(options); } - }, - shift: function () { - this.input = function (channel, control, value, status) { - if (components.Button.prototype.isPress(channel, control, value, status)) { - engine.setValue(this.group, 'rateSearch', this.seekRate); - } else { + unshift() { + this.inKey = this.cueName + '_activate'; + this.input = components.Button.prototype.input; + // Avoid log spam on startup + if (this.group !== undefined) { engine.setValue(this.group, 'rateSearch', 0); } - }; - }, - supershift: function () { - this.inKey = this.cueName + '_clear'; - this.input = components.Button.prototype.input; - engine.setValue(this.group, 'rateSearch', 0); - } - }); - - this.bottomButtonLayers.intro_outro = new components.ComponentContainer(); - this.bottomButtonLayers.intro_outro[1] = new CueAndSeekButton({ - cueName: "intro_start", - seekRate: XoneK2.seekRateFast, - color: XoneK2.color.amber, - }); - this.bottomButtonLayers.intro_outro[2] = new CueAndSeekButton({ - cueName: "intro_end", - seekRate: -1 * XoneK2.seekRateFast, - color: XoneK2.color.amber, - }); - this.bottomButtonLayers.intro_outro[3] = new CueAndSeekButton({ - cueName: "outro_start", - seekRate: XoneK2.seekRateSlow, - color: XoneK2.color.amber, - }); - this.bottomButtonLayers.intro_outro[4] = new CueAndSeekButton({ - cueName: "outro_end", - seekRate: -1 * XoneK2.seekRateSlow, - color: XoneK2.color.amber, - }); - - - this.bottomButtonLayers.hotcue = new components.ComponentContainer(); - this.bottomButtonLayers.hotcue[1] = new CueAndSeekButton({ - cueName: "hotcue_1", - seekRate: XoneK2.seekRateFast, - color: XoneK2.color.red, - }); - this.bottomButtonLayers.hotcue[2] = new CueAndSeekButton({ - cueName: "hotcue_2", - seekRate: -1 * XoneK2.seekRateFast, - color: XoneK2.color.red, - }); - this.bottomButtonLayers.hotcue[3] = new CueAndSeekButton({ - cueName: "hotcue_3", - seekRate: XoneK2.seekRateSlow, - color: XoneK2.color.red, - }); - this.bottomButtonLayers.hotcue[4] = new CueAndSeekButton({ - cueName: "hotcue_4", - seekRate: -1 * XoneK2.seekRateSlow, - color: XoneK2.color.red, - }); - - - this.bottomButtonLayers.loop = new components.ComponentContainer(); - - this.bottomButtonLayers.loop[1] = new components.Button({ - outKey: 'loop_enabled', - unshift: function () { - this.inKey = 'reloop_toggle'; - }, - shift: function () { - this.inKey = 'reloop_andstop'; - }, - supershift: function () { - this.inKey = 'loop_in'; - }, - color: XoneK2.color.red, - }); - - this.bottomButtonLayers.loop[2] = new components.Button({ - unshift: function () { - this.inKey = 'beatloop_activate'; - }, - shift: function () { - this.inKey = 'beatlooproll_activate'; - }, - supershift: function () { - this.inKey = 'loop_out'; - }, - trigger: function() { - this.send(this.on); - }, - color: XoneK2.color.green, - }); - - this.bottomButtonLayers.loop[3] = new components.Button({ - unshift: function () { - this.inKey = 'loop_double'; - this.input = components.Button.prototype.input; - }, - shift: function () { - this.inKey = 'beatjump_forward'; - this.input = components.Button.prototype.input; - }, - supershift: function () { - this.input = function (channel, control, value, status) { - if (this.isPress(channel, control, value, status)) { - engine.setValue(this.group, 'beatjump_size', - engine.getValue(this.group, 'beatjump_size') * 2); - } - }; - }, - trigger: function() { - this.send(this.on); - }, - color: XoneK2.color.amber, - }); - - this.bottomButtonLayers.loop[4] = new components.Button({ - unshift: function () { - this.inKey = 'loop_halve'; - this.input = components.Button.prototype.input; - }, - shift: function () { - this.inKey = 'beatjump_backward'; - this.input = components.Button.prototype.input; - }, - supershift: function () { - this.input = function (channel, control, value, status) { - if (this.isPress(channel, control, value, status)) { - engine.setValue(this.group, 'beatjump_size', - engine.getValue(this.group, 'beatjump_size') / 2); - } - }; - }, - trigger: function() { - this.send(this.on); - }, - color: XoneK2.color.amber, - }); - - var setGroup = function (component) { - if (component.group === undefined) { - component.group = theDeck.deckString; - } - }; + } + shift() { + this.input = function (channel, control, value, status) { + if (components.Button.prototype.isPress(channel, control, value, status)) { + engine.setValue(this.group, 'rateSearch', this.seekRate); + } else { + engine.setValue(this.group, 'rateSearch', 0); + } + }; + } + supershift() { + this.inKey = this.cueName + '_clear'; + this.input = components.Button.prototype.input; + engine.setValue(this.group, 'rateSearch', 0); + } + }; - for (var memberName in this.bottomButtonLayers) { - if (this.bottomButtonLayers.hasOwnProperty(memberName)) { - XoneK2.setBottomButtonsMidi(this.bottomButtonLayers[memberName], column, midiChannel); - this.bottomButtonLayers[memberName].forEachComponent(setGroup); - } - } + this.bottomButtonLayers.intro_outro = new components.ComponentContainer(); + this.bottomButtonLayers.intro_outro[1] = new CueAndSeekButton({ + cueName: "intro_start", + seekRate: XoneK2.seekRateFast, + color: XoneK2.color.amber, + }); + this.bottomButtonLayers.intro_outro[2] = new CueAndSeekButton({ + cueName: "intro_end", + seekRate: -1 * XoneK2.seekRateFast, + color: XoneK2.color.amber, + }); + this.bottomButtonLayers.intro_outro[3] = new CueAndSeekButton({ + cueName: "outro_start", + seekRate: XoneK2.seekRateSlow, + color: XoneK2.color.amber, + }); + this.bottomButtonLayers.intro_outro[4] = new CueAndSeekButton({ + cueName: "outro_end", + seekRate: -1 * XoneK2.seekRateSlow, + color: XoneK2.color.amber, + }); + + + this.bottomButtonLayers.hotcue = new components.ComponentContainer(); + this.bottomButtonLayers.hotcue[1] = new CueAndSeekButton({ + cueName: "hotcue_1", + seekRate: XoneK2.seekRateFast, + color: XoneK2.color.red, + }); + this.bottomButtonLayers.hotcue[2] = new CueAndSeekButton({ + cueName: "hotcue_2", + seekRate: -1 * XoneK2.seekRateFast, + color: XoneK2.color.red, + }); + this.bottomButtonLayers.hotcue[3] = new CueAndSeekButton({ + cueName: "hotcue_3", + seekRate: XoneK2.seekRateSlow, + color: XoneK2.color.red, + }); + this.bottomButtonLayers.hotcue[4] = new CueAndSeekButton({ + cueName: "hotcue_4", + seekRate: -1 * XoneK2.seekRateSlow, + color: XoneK2.color.red, + }); + + + this.bottomButtonLayers.loop = new components.ComponentContainer(); + + this.bottomButtonLayers.loop[1] = new components.Button({ + outKey: 'loop_enabled', + unshift: function () { + this.inKey = 'reloop_toggle'; + }, + shift: function () { + this.inKey = 'reloop_andstop'; + }, + supershift: function () { + this.inKey = 'loop_in'; + }, + color: XoneK2.color.red, + }); + + this.bottomButtonLayers.loop[2] = new components.Button({ + unshift: function () { + this.inKey = 'beatloop_activate'; + }, + shift: function () { + this.inKey = 'beatlooproll_activate'; + }, + supershift: function () { + this.inKey = 'loop_out'; + }, + trigger: function() { + this.send(this.on); + }, + color: XoneK2.color.green, + }); + + this.bottomButtonLayers.loop[3] = new components.Button({ + unshift: function () { + this.inKey = 'loop_double'; + this.input = components.Button.prototype.input; + }, + shift: function () { + this.inKey = 'beatjump_forward'; + this.input = components.Button.prototype.input; + }, + supershift: function () { + this.input = function (channel, control, value, status) { + if (this.isPress(channel, control, value, status)) { + engine.setValue(this.group, 'beatjump_size', + engine.getValue(this.group, 'beatjump_size') * 2); + } + }; + }, + trigger: function() { + this.send(this.on); + }, + color: XoneK2.color.amber, + }); + + this.bottomButtonLayers.loop[4] = new components.Button({ + unshift: function () { + this.inKey = 'loop_halve'; + this.input = components.Button.prototype.input; + }, + shift: function () { + this.inKey = 'beatjump_backward'; + this.input = components.Button.prototype.input; + }, + supershift: function () { + this.input = function (channel, control, value, status) { + if (this.isPress(channel, control, value, status)) { + engine.setValue(this.group, 'beatjump_size', + engine.getValue(this.group, 'beatjump_size') / 2); + } + }; + }, + trigger: function() { + this.send(this.on); + }, + color: XoneK2.color.amber, + }); + + var setGroup = function (component) { + if (component.group === undefined) { + component.group = theDeck.deckString; + } + }; - this.bottomButtons = this.bottomButtonLayers[XoneK2.deckBottomButtonLayers[0].name]; + for (var memberName in this.bottomButtonLayers) { + if (this.bottomButtonLayers.hasOwnProperty(memberName)) { + XoneK2.setBottomButtonsMidi(this.bottomButtonLayers[memberName], column, midiChannel); + this.bottomButtonLayers[memberName].forEachComponent(setGroup); + } + } - XoneK2.setColumnMidi(this, column, midiChannel); - this.reconnectComponents(setGroup); + this.bottomButtons = this.bottomButtonLayers[XoneK2.deckBottomButtonLayers[0].name]; + XoneK2.setColumnMidi(this, column, midiChannel); + this.reconnectComponents(setGroup); + } }; -XoneK2.Deck.prototype = new components.Deck(); XoneK2.decksLayerButton = function (channel, control, value, status) { if (!XoneK2.controllers[channel].isShifted) { @@ -691,251 +662,253 @@ XoneK2.decksLayerButton = function (channel, control, value, status) { } }; -XoneK2.EffectUnit = function (column, unitNumber, midiChannel, twoDeck) { - // "library" refers to the Components library - // This is a private variable rather than a property of XoneK2.EffectUnit - // so that components.ComponentContainer.prototype.shift/unshift do not - // call the shift/unshift methods of the components in libraryEffectUnit - // when a single effect unit is focused. - var libraryEffectUnit = new components.EffectUnit([unitNumber], false, { - unfocused: XoneK2.color.red, - focusChooseMode: XoneK2.color.green, - focused: XoneK2.color.amber, - }); - - var unitString = '[EffectRack1_EffectUnit' + unitNumber + ']'; - - this.hadParametersShowing = engine.getValue(unitString, 'show_parameters'); - this.hadFocusShowing = engine.getValue(unitString, 'show_focus'); - - this.fader = libraryEffectUnit.dryWetKnob; - - this.bottomButtons = new components.ComponentContainer(); - var channelString; - libraryEffectUnit.enableOnChannelButtons.addButton('Channel1'); - this.bottomButtons[1] = libraryEffectUnit.enableOnChannelButtons.Channel1; - libraryEffectUnit.enableOnChannelButtons.addButton('Channel2'); - this.bottomButtons[2] = libraryEffectUnit.enableOnChannelButtons.Channel2; - if (twoDeck === true) { - libraryEffectUnit.enableOnChannelButtons.addButton('Master'); - this.bottomButtons[3] = libraryEffectUnit.enableOnChannelButtons.Master; - libraryEffectUnit.enableOnChannelButtons.addButton('Headphone'); - this.bottomButtons[4] = libraryEffectUnit.enableOnChannelButtons.Headphone; - } else { - this.bottomButtons[3] = new components.Button({ - group: unitString, - unshift: function () { - this.disconnect(); - this.inKey = 'group_[Channel3]_enable'; - this.outKey = 'group_[Channel3]_enable'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - shift: function () { - this.disconnect(); - this.inKey = 'group_[Master]_enable'; - this.outKey = 'group_[Master]_enable'; - this.color = XoneK2.color.amber; - this.connect(); - this.trigger(); - }, - type: components.Button.prototype.types.toggle, - }); - this.bottomButtons[4] = new components.Button({ - group: unitString, - unshift: function () { - this.disconnect(); - this.inKey = 'group_[Channel4]_enable'; - this.outKey = 'group_[Channel4]_enable'; - this.color = XoneK2.color.red; - this.connect(); - this.trigger(); - }, - shift: function () { - this.disconnect(); - this.inKey = 'group_[Headphone]_enable'; - this.outKey = 'group_[Headphone]_enable'; - this.color = XoneK2.color.amber; - this.connect(); - this.trigger(); - }, - type: components.Button.prototype.types.toggle, - }); - } - - this.encoder = new components.Component({ - // TODO: figure out a use for this. Maybe switching chain presets? - input: function () {}, - }); - - this.topButtons = new components.ComponentContainer(); - this.knobs = new components.ComponentContainer(); - - this.useLibraryEffectUnit = function () { - //print('*************************************************** COLUMN ' - // + column + ' USING LIBRARY UNIT'); - - this.knobs.forEachComponent(function (component) { - component.disconnect(); +XoneK2.EffectUnit = class extends components.ComponentContainer { + constructor(column, unitNumber, midiChannel, twoDeck) { + super(); + // "library" refers to the Components library + // This is a private variable rather than a property of XoneK2.EffectUnit + // so that components.ComponentContainer.prototype.shift/unshift do not + // call the shift/unshift methods of the components in libraryEffectUnit + // when a single effect unit is focused. + var libraryEffectUnit = new components.EffectUnit([unitNumber], false, { + unfocused: XoneK2.color.red, + focusChooseMode: XoneK2.color.green, + focused: XoneK2.color.amber, }); - this.topButtons.forEachComponent(function (component) { - component.disconnect(); - }); - - this.encoderPress = libraryEffectUnit.effectFocusButton; - this.knobs = libraryEffectUnit.knobs; - this.topButtons = libraryEffectUnit.enableButtons; - engine.setValue(unitString, 'show_focus', this.hadFocusShowing); - engine.setValue(unitString, 'show_parameters', this.hadParametersShowing); - - XoneK2.setColumnMidi(this, column, midiChannel); - if (libraryEffectUnit.hasInitialized) { - libraryEffectUnit.showParametersConnection = - engine.makeConnection(unitString, - 'show_parameters', - libraryEffectUnit.onShowParametersChange.bind(this)); - - libraryEffectUnit.knobs.reconnectComponents(); - libraryEffectUnit.enableButtons.reconnectComponents(); - libraryEffectUnit.effectFocusButton.connect(); - libraryEffectUnit.effectFocusButton.trigger(); - libraryEffectUnit.showParametersConnection.trigger(); + var unitString = '[EffectRack1_EffectUnit' + unitNumber + ']'; + + this.hadParametersShowing = engine.getValue(unitString, 'show_parameters'); + this.hadFocusShowing = engine.getValue(unitString, 'show_focus'); + + this.fader = libraryEffectUnit.dryWetKnob; + + this.bottomButtons = new components.ComponentContainer(); + var channelString; + libraryEffectUnit.enableOnChannelButtons.addButton('Channel1'); + this.bottomButtons[1] = libraryEffectUnit.enableOnChannelButtons.Channel1; + libraryEffectUnit.enableOnChannelButtons.addButton('Channel2'); + this.bottomButtons[2] = libraryEffectUnit.enableOnChannelButtons.Channel2; + if (twoDeck === true) { + libraryEffectUnit.enableOnChannelButtons.addButton('Master'); + this.bottomButtons[3] = libraryEffectUnit.enableOnChannelButtons.Master; + libraryEffectUnit.enableOnChannelButtons.addButton('Headphone'); + this.bottomButtons[4] = libraryEffectUnit.enableOnChannelButtons.Headphone; } else { - libraryEffectUnit.init(); + this.bottomButtons[3] = new components.Button({ + group: unitString, + unshift: function () { + this.disconnect(); + this.inKey = 'group_[Channel3]_enable'; + this.outKey = 'group_[Channel3]_enable'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + shift: function () { + this.disconnect(); + this.inKey = 'group_[Master]_enable'; + this.outKey = 'group_[Master]_enable'; + this.color = XoneK2.color.amber; + this.connect(); + this.trigger(); + }, + type: components.Button.prototype.types.toggle, + }); + this.bottomButtons[4] = new components.Button({ + group: unitString, + unshift: function () { + this.disconnect(); + this.inKey = 'group_[Channel4]_enable'; + this.outKey = 'group_[Channel4]_enable'; + this.color = XoneK2.color.red; + this.connect(); + this.trigger(); + }, + shift: function () { + this.disconnect(); + this.inKey = 'group_[Headphone]_enable'; + this.outKey = 'group_[Headphone]_enable'; + this.color = XoneK2.color.amber; + this.connect(); + this.trigger(); + }, + type: components.Button.prototype.types.toggle, + }); } - }; - this.useLibraryEffectUnit(); - - this.unitFocusButton = new components.Button({ - input: function (channel, control, value, status) { - if (this.isPress(channel, control, value, status)) { - if (XoneK2.controllers[channel].focusedEffectUnit === unitNumber) { - // Prevent flickering - return; - } + this.encoder = new components.Component({ + // TODO: figure out a use for this. Maybe switching chain presets? + input: function () {}, + }); - for (var x = 1; x <= 4; ++x) { - var effectUnitColumn = XoneK2.controllers[channel].columns[x]; - if (!(effectUnitColumn instanceof XoneK2.EffectUnit)) { - continue; - } + this.topButtons = new components.ComponentContainer(); + this.knobs = new components.ComponentContainer(); - XoneK2.controllers[channel].focusedEffectUnit = unitNumber; - effectUnitColumn.focusUnit(unitNumber); - } - } - }, - color: XoneK2.color.red, - }); - XoneK2.setTopEncoderPressMidi(this.unitFocusButton, column, midiChannel); + this.useLibraryEffectUnit = function () { + //print('*************************************************** COLUMN ' + // + column + ' USING LIBRARY UNIT'); - this.disconnectShowParameters = function () { - libraryEffectUnit.showParametersConnection.disconnect(); - }; + this.knobs.forEachComponent(function (component) { + component.disconnect(); + }); + this.topButtons.forEachComponent(function (component) { + component.disconnect(); + }); - this.focusUnit = function (focusedUnitNumber) { - //print('================================================== COLUMN ' - // + column + ' FOCUSING UNIT ' + focusedUnitNumber); - - libraryEffectUnit.effectFocusButton.disconnect(); - // The showParametersConnection connection does not belong to any specific - // Component, so it must be disconnected manually. This script creates - // objects for every potential layout on different MIDI channels. The - // showParametersConnection for every XoneK2.EffectUnit must be disconnected - // or the connections for other MIDI channels will interfere with - // the MIDI channel actually being used. - for (var n = 0; n <= 0xF; n++) { - var col = XoneK2.controllers[n].columns[column]; - if (col instanceof XoneK2.EffectUnit) { - col.disconnectShowParameters(); + this.encoderPress = libraryEffectUnit.effectFocusButton; + this.knobs = libraryEffectUnit.knobs; + this.topButtons = libraryEffectUnit.enableButtons; + + engine.setValue(unitString, 'show_focus', this.hadFocusShowing); + engine.setValue(unitString, 'show_parameters', this.hadParametersShowing); + + XoneK2.setColumnMidi(this, column, midiChannel); + if (libraryEffectUnit.hasInitialized) { + libraryEffectUnit.showParametersConnection = + engine.makeConnection(unitString, + 'show_parameters', + libraryEffectUnit.onShowParametersChange.bind(this)); + + libraryEffectUnit.knobs.reconnectComponents(); + libraryEffectUnit.enableButtons.reconnectComponents(); + libraryEffectUnit.effectFocusButton.connect(); + libraryEffectUnit.effectFocusButton.trigger(); + libraryEffectUnit.showParametersConnection.trigger(); + } else { + libraryEffectUnit.init(); } - } - libraryEffectUnit.showParametersConnection.disconnect(); - this.knobs.forEachComponent(function (component) { - component.disconnect(); - }); - this.topButtons.forEachComponent(function (component) { - component.disconnect(); - }); - - if (!XoneK2.controllers[midiChannel].singleEffectUnitModeActive) { - this.hadFocusShowing = engine.getValue(unitString, 'show_focus'); - this.hadParametersShowing = engine.getValue(unitString, 'show_parameters'); - } - engine.setValue(unitString, 'show_focus', 0); - engine.setValue(unitString, 'show_parameters', focusedUnitNumber === unitNumber); - this.encoderPress = this.unitFocusButton; - this.unitFocusButton.send(focusedUnitNumber === unitNumber); + }; + this.useLibraryEffectUnit(); - // The containers must be reassigned to new objects before reassigning - // the Components within them. Otherwise, the Components in - // libraryEffectUnit will get reassigned too. - this.knobs = new components.ComponentContainer(); - this.topButtons = new components.ComponentContainer(); - for (var k = 1; k <= 3; k++) { - this.knobs[k] = new components.Pot({ - group: '[EffectRack1_EffectUnit' + focusedUnitNumber + '_Effect' + k + ']', - inKey: 'parameter' + column, - unshift: function () { - this.input = function (channel, control, value, status, group) { - this.inSetParameter(this.inValueScale(value)); + this.unitFocusButton = new components.Button({ + input: function (channel, control, value, status) { + if (this.isPress(channel, control, value, status)) { + if (XoneK2.controllers[channel].focusedEffectUnit === unitNumber) { + // Prevent flickering + return; + } - if (this.previousValueReceived === undefined) { - engine.softTakeover(this.group, this.inKey, true); - } - this.previousValueReceived = value; - }; - }, - shift: function () { - engine.softTakeoverIgnoreNextValue(this.group, this.inKey); - this.valueAtLastEffectSwitch = this.previousValueReceived; - // Floor the threshold to ensure that every effect can be selected - this.changeThreshold = Math.floor(this.max / - engine.getValue('[Master]', 'num_effectsavailable')); - - this.input = function (channel, control, value, status, group) { - var change = value - this.valueAtLastEffectSwitch; - if (Math.abs(change) >= this.changeThreshold - // this.valueAtLastEffectSwitch can be undefined if - // shift was pressed before the first MIDI value was received. - || this.valueAtLastEffectSwitch === undefined) { - engine.setValue(this.group, 'effect_selector', change); - this.valueAtLastEffectSwitch = value; + for (var x = 1; x <= 4; ++x) { + var effectUnitColumn = XoneK2.controllers[channel].columns[x]; + if (!(effectUnitColumn instanceof XoneK2.EffectUnit)) { + continue; } - this.previousValueReceived = value; - }; - }, + XoneK2.controllers[channel].focusedEffectUnit = unitNumber; + effectUnitColumn.focusUnit(unitNumber); + } + } + }, + color: XoneK2.color.red, + }); + XoneK2.setTopEncoderPressMidi(this.unitFocusButton, column, midiChannel); + + this.disconnectShowParameters = function () { + libraryEffectUnit.showParametersConnection.disconnect(); + }; + + this.focusUnit = function (focusedUnitNumber) { + //print('================================================== COLUMN ' + // + column + ' FOCUSING UNIT ' + focusedUnitNumber); + + libraryEffectUnit.effectFocusButton.disconnect(); + // The showParametersConnection connection does not belong to any specific + // Component, so it must be disconnected manually. This script creates + // objects for every potential layout on different MIDI channels. The + // showParametersConnection for every XoneK2.EffectUnit must be disconnected + // or the connections for other MIDI channels will interfere with + // the MIDI channel actually being used. + for (var n = 0; n <= 0xF; n++) { + var col = XoneK2.controllers[n].columns[column]; + if (col instanceof XoneK2.EffectUnit) { + col.disconnectShowParameters(); + } + } + libraryEffectUnit.showParametersConnection.disconnect(); + this.knobs.forEachComponent(function (component) { + component.disconnect(); + }); + this.topButtons.forEachComponent(function (component) { + component.disconnect(); }); - if (column === 1) { - this.topButtons[k] = new components.Button({ - group: '[EffectRack1_EffectUnit' + focusedUnitNumber + '_Effect' + k + ']', - key: 'enabled', - type: components.Button.prototype.types.powerWindow, - color: XoneK2.color.amber, - outConnect: false, // midi is not defined yet - }); - } else { - this.topButtons[k] = new components.Button({ + if (!XoneK2.controllers[midiChannel].singleEffectUnitModeActive) { + this.hadFocusShowing = engine.getValue(unitString, 'show_focus'); + this.hadParametersShowing = engine.getValue(unitString, 'show_parameters'); + } + engine.setValue(unitString, 'show_focus', 0); + engine.setValue(unitString, 'show_parameters', focusedUnitNumber === unitNumber); + + this.encoderPress = this.unitFocusButton; + this.unitFocusButton.send(focusedUnitNumber === unitNumber); + + // The containers must be reassigned to new objects before reassigning + // the Components within them. Otherwise, the Components in + // libraryEffectUnit will get reassigned too. + this.knobs = new components.ComponentContainer(); + this.topButtons = new components.ComponentContainer(); + for (var k = 1; k <= 3; k++) { + this.knobs[k] = new components.Pot({ group: '[EffectRack1_EffectUnit' + focusedUnitNumber + '_Effect' + k + ']', - key: 'button_parameter' + (column-1), - type: components.Button.prototype.types.powerWindow, - color: XoneK2.color.green, - outConnect: false, // midi is not defined yet + inKey: 'parameter' + column, + unshift: function () { + this.input = function (channel, control, value, status, group) { + this.inSetParameter(this.inValueScale(value)); + + if (this.previousValueReceived === undefined) { + engine.softTakeover(this.group, this.inKey, true); + } + this.previousValueReceived = value; + }; + }, + shift: function () { + engine.softTakeoverIgnoreNextValue(this.group, this.inKey); + this.valueAtLastEffectSwitch = this.previousValueReceived; + // Floor the threshold to ensure that every effect can be selected + this.changeThreshold = Math.floor(this.max / + engine.getValue('[Master]', 'num_effectsavailable')); + + this.input = function (channel, control, value, status, group) { + var change = value - this.valueAtLastEffectSwitch; + if (Math.abs(change) >= this.changeThreshold + // this.valueAtLastEffectSwitch can be undefined if + // shift was pressed before the first MIDI value was received. + || this.valueAtLastEffectSwitch === undefined) { + engine.setValue(this.group, 'effect_selector', change); + this.valueAtLastEffectSwitch = value; + } + + this.previousValueReceived = value; + }; + }, }); + + if (column === 1) { + this.topButtons[k] = new components.Button({ + group: '[EffectRack1_EffectUnit' + focusedUnitNumber + '_Effect' + k + ']', + key: 'enabled', + type: components.Button.prototype.types.powerWindow, + color: XoneK2.color.amber, + outConnect: false, // midi is not defined yet + }); + } else { + this.topButtons[k] = new components.Button({ + group: '[EffectRack1_EffectUnit' + focusedUnitNumber + '_Effect' + k + ']', + key: 'button_parameter' + (column-1), + type: components.Button.prototype.types.powerWindow, + color: XoneK2.color.green, + outConnect: false, // midi is not defined yet + }); + } } - } - XoneK2.setTopButtonsMidi(this.topButtons, column, midiChannel); - this.knobs.reconnectComponents(); - this.topButtons.reconnectComponents(); - }; + XoneK2.setTopButtonsMidi(this.topButtons, column, midiChannel); + this.knobs.reconnectComponents(); + this.topButtons.reconnectComponents(); + }; + } }; -XoneK2.EffectUnit.prototype = new components.ComponentContainer(); // This is only used for the 4 effect unit layouts XoneK2.effectsLayerButton = function (channel, control, value, status) {