summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine C <mixxx@acolombier.dev>2023-04-02 21:31:55 +0100
committerAntoine C <mixxx@acolombier.dev>2023-06-04 17:25:04 +0100
commite1f7efc80a1e583ea10eb25c4a9df777c59b1342 (patch)
treeb4c5c268dcad9102312c9e0be8190deb661a4046
parent951e8e87f6b8d4474aa0565457cf83e6291b5078 (diff)
Kontrol S4 Mk3: adding input mixer feature
-rw-r--r--res/controllers/Traktor-Kontrol-S4-MK3.js121
1 files changed, 101 insertions, 20 deletions
diff --git a/res/controllers/Traktor-Kontrol-S4-MK3.js b/res/controllers/Traktor-Kontrol-S4-MK3.js
index ea4a2ce7a3..f668a24612 100644
--- a/res/controllers/Traktor-Kontrol-S4-MK3.js
+++ b/res/controllers/Traktor-Kontrol-S4-MK3.js
@@ -107,6 +107,10 @@ const GridButtonBlinkOverBeat = false;
// Default: true
const WheelLedBlinkOnTrackEnd = true;
+// When shifting either decks, the mixer will control microphones or auxiliary lines. If there is both a mic and an configure on the same channel, the mixer will control the auxiliary.
+// Default: true
+const MixerControlsMixAnxOnShift = true;
+
// Define how many wheel moves are sampled to compute the speed. The more you have, the more the speed is accurate, but the
// less responsive it gets in Mixxx. Default: 5
const WheelSpeedSample = 3;
@@ -404,6 +408,7 @@ class ComponentContainer extends Component {
}
component.shifted = false;
}
+ this.shifted = false;
}
shift() {
for (const component of this) {
@@ -412,6 +417,7 @@ class ComponentContainer extends Component {
}
component.shifted = true;
}
+ this.shifted = true;
}
}
@@ -964,6 +970,10 @@ class Pot extends Component {
super(options);
this.hardwarePosition = null;
this.shiftedHardwarePosition = null;
+
+ if (this.input === undefined) {
+ this.input = this.defaultInput;
+ }
}
setGroupKey(group, key) {
this.inKey = key;
@@ -975,7 +985,7 @@ class Pot extends Component {
this.outKey = key;
this.outConnect();
}
- input(value) {
+ defaultInput(value) {
const receivingFirstValue = this.hardwarePosition === null;
this.hardwarePosition = value / this.max;
engine.setParameter(this.group, this.inKey, this.hardwarePosition);
@@ -998,7 +1008,7 @@ class Mixer extends ComponentContainer {
this.outReport = outReports[128];
- this.mixerColumnDeck1 = new S4Mk3MixerColumn("[Channel1]", inReports, outReports[128],
+ this.mixerColumnDeck1 = new S4Mk3MixerColumn(1, inReports, outReports[128],
{
saveGain: {inByte: 12, inBit: 0, outByte: 80},
effectUnit1Assign: {inByte: 3, inBit: 3, outByte: 78},
@@ -1014,7 +1024,7 @@ class Mixer extends ComponentContainer {
crossfaderSwitch: {inByte: 18, inBit: 4},
}
);
- this.mixerColumnDeck2 = new S4Mk3MixerColumn("[Channel2]", inReports, outReports[128],
+ this.mixerColumnDeck2 = new S4Mk3MixerColumn(2, inReports, outReports[128],
{
saveGain: {inByte: 12, inBit: 1, outByte: 84},
effectUnit1Assign: {inByte: 3, inBit: 5, outByte: 82},
@@ -1029,7 +1039,7 @@ class Mixer extends ComponentContainer {
crossfaderSwitch: {inByte: 18, inBit: 2},
}
);
- this.mixerColumnDeck3 = new S4Mk3MixerColumn("[Channel3]", inReports, outReports[128],
+ this.mixerColumnDeck3 = new S4Mk3MixerColumn(3, inReports, outReports[128],
{
saveGain: {inByte: 3, inBit: 1, outByte: 88},
effectUnit1Assign: {inByte: 3, inBit: 0, outByte: 86},
@@ -1044,7 +1054,7 @@ class Mixer extends ComponentContainer {
crossfaderSwitch: {inByte: 18, inBit: 6},
}
);
- this.mixerColumnDeck4 = new S4Mk3MixerColumn("[Channel4]", inReports, outReports[128],
+ this.mixerColumnDeck4 = new S4Mk3MixerColumn(4, inReports, outReports[128],
{
saveGain: {inByte: 12, inBit: 2, outByte: 92},
effectUnit1Assign: {inByte: 3, inBit: 7, outByte: 90},
@@ -1531,7 +1541,7 @@ class S4Mk3EffectUnit extends ComponentContainer {
}
class S4Mk3Deck extends Deck {
- constructor(decks, colors, effectUnit, inReports, outReport, io) {
+ constructor(decks, colors, effectUnit, mixer, inReports, outReport, io) {
super(decks, colors);
this.playButton = new PlayButton({
@@ -1541,7 +1551,9 @@ class S4Mk3Deck extends Deck {
this.cueButton = new CueButton({
deck: this
});
+
this.effectUnit = effectUnit;
+ this.mixer = mixer;
this.syncMasterButton = new Button({
key: "sync_leader",
@@ -2584,32 +2596,44 @@ class S4Mk3Deck extends Deck {
}
class S4Mk3MixerColumn extends ComponentContainer {
- constructor(group, inReports, outReport, io) {
+ constructor(idx, inReports, outReport, io) {
super();
- this.group = group;
+ this.idx = idx;
+ this.group = "[Channel" + idx + "]";
this.gain = new Pot({
inKey: "pregain",
});
this.eqHigh = new Pot({
- group: "[EqualizerRack1_" + group + "_Effect1]",
+ group: "[EqualizerRack1_" + this.group + "_Effect1]",
inKey: "parameter3",
});
this.eqMid = new Pot({
- group: "[EqualizerRack1_" + group + "_Effect1]",
+ group: "[EqualizerRack1_" + this.group + "_Effect1]",
inKey: "parameter2",
});
this.eqLow = new Pot({
- group: "[EqualizerRack1_" + group + "_Effect1]",
+ group: "[EqualizerRack1_" + this.group + "_Effect1]",
inKey: "parameter1",
});
this.quickEffectKnob = new Pot({
- group: "[QuickEffectRack1_" + group + "]",
+ group: "[QuickEffectRack1_" + this.group + "]",
inKey: "super1",
});
this.volume = new Pot({
inKey: "volume",
+ mixer: this,
+ input: MixerControlsMixAnxOnShift ? function(value) {
+ if (this.mixer.shifted) {
+ const controlKey = (this.group === "[Microphone" + this.mixer.idx + "]" || this.group === "[Microphone]") ? "talkover" : "master";
+ const isPlaying = engine.getValue(this.group, controlKey);
+ if ((value !== 0) !== isPlaying) {
+ engine.setValue(this.group, controlKey, value !== 0);
+ }
+ }
+ this.defaultInput(value);
+ } : undefined
});
this.pfl = new ToggleButton({
@@ -2667,6 +2691,55 @@ class S4Mk3MixerColumn extends ComponentContainer {
}
}
}
+
+ if (MixerControlsMixAnxOnShift) {
+ this.shift = function() {
+ engine.setValue("[Microphone]", "show_microphone", true);
+ this.updateGroup(true);
+ };
+
+ this.unshift = function() {
+ engine.setValue("[Microphone]", "show_microphone", false);
+ this.updateGroup(false);
+ };
+ }
+ }
+
+ updateGroup(shifted) {
+ let alternativeInput = null;
+ if (engine.getValue("[Auxiliary" + this.idx + "]", "input_configured")) {
+ alternativeInput = "[Auxiliary" + this.idx + "]";
+ } else if (engine.getValue(this.idx !== 1 ? "[Microphone" + this.idx + "]" : "[Microphone]", "input_configured")) {
+ alternativeInput = this.idx !== 1 ? "[Microphone" + this.idx + "]" : "[Microphone]";
+ }
+
+ if (!alternativeInput) {
+ return;
+ }
+ this.group = shifted ? alternativeInput : "[Channel" + this.idx + "]";
+ for (const property of ["gain", "volume", "pfl", "crossfaderSwitch"]) {
+ const component = this[property];
+ if (component instanceof Component) {
+ component.outDisconnect();
+ component.inDisconnect();
+ component.group = this.group;
+ component.inConnect();
+ component.outConnect();
+ component.outTrigger();
+ }
+ }
+ for (const property of ["effectUnit1Assign", "effectUnit2Assign"]) {
+ const component = this[property];
+ if (component instanceof Component) {
+ component.outDisconnect();
+ component.inDisconnect();
+ component.inKey = "group_" + this.group + "_enable";
+ component.outKey = "group_" + this.group + "_enable";
+ component.inConnect();
+ component.outConnect();
+ component.outTrigger();
+ }
+ }
}
}
@@ -2723,11 +2796,16 @@ class S4MK3 {
}
);
+ // The interaction between the FX SELECT buttons and the QuickEffect enable buttons is rather complex.
+ // It is easier to have this separate from the S4Mk3MixerColumn dhe FX SELECT buttons are not
+ // really in the mixer columns.
+ this.mixer = new Mixer(this.inReports, this.outReports);
+
// There is no consistent offset between the left and right deck,
// so every single components' IO needs to be specified individually
// for both decks.
this.leftDeck = new S4Mk3Deck(
- [1, 3], [DeckColors[0], DeckColors[2]], this.effectUnit1,
+ [1, 3], [DeckColors[0], DeckColors[2]], this.effectUnit1, this.mixer,
this.inReports, this.outReports[128],
{
playButton: {inByte: 5, inBit: 0, outByte: 55},
@@ -2778,7 +2856,7 @@ class S4MK3 {
);
this.rightDeck = new S4Mk3Deck(
- [2, 4], [DeckColors[1], DeckColors[3]], this.effectUnit2,
+ [2, 4], [DeckColors[1], DeckColors[3]], this.effectUnit2, this.mixer,
this.inReports, this.outReports[128],
{
playButton: {inByte: 13, inBit: 0, outByte: 66},
@@ -2828,18 +2906,21 @@ class S4MK3 {
}
);
- // The interaction between the FX SELECT buttons and the QuickEffect enable buttons is rather complex.
- // It is easier to have this separate from the S4Mk3MixerColumn class and the FX SELECT buttons are not
- // really in the mixer columns.
- this.mixer = new Mixer(this.inReports, this.outReports);
-
+ const that = this;
/* eslint no-unused-vars: "off" */
const meterConnection = engine.makeConnection("[Master]", "guiTick50ms", function(_value) {
const deckMeters = Array(78).fill(0);
// Each column has 14 segments, but treat the top one specially for the clip indicator.
const deckSegments = 13;
for (let deckNum = 1; deckNum <= 4; deckNum++) {
- const deckGroup = "[Channel" + deckNum + "]";
+ let deckGroup = "[Channel" + deckNum + "]";
+ if (that.leftDeck.shifted || that.rightDeck.shifted) {
+ if (engine.getValue("[Auxiliary" + deckNum + "]", "input_configured")) {
+ deckGroup = "[Auxiliary" + deckNum + "]";
+ } else if (engine.getValue(deckNum !== 1 ? "[Microphone" + deckNum + "]" : "[Microphone]", "input_configured")) {
+ deckGroup = deckNum !== 1 ? "[Microphone" + deckNum + "]" : "[Microphone]";
+ }
+ }
const deckLevel = engine.getValue(deckGroup, "VuMeter");
const columnBaseIndex = (deckNum - 1) * (deckSegments + 2);
const scaledLevel = deckLevel * deckSegments;