Skip to content

Commit 7fc7abe

Browse files
ES6 ComponentsJS
1 parent c0b4f50 commit 7fc7abe

3 files changed

Lines changed: 226 additions & 9 deletions

File tree

res/controllers/engine-api.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
21
/** ScriptConnectionJSProxy */
3-
42
declare interface ScriptConnection {
53
/**
64
* Disconnect the script connection,

res/controllers/midi-components-0.0.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Components JS library for Mixxx
33
* Documentation is on the Mixxx wiki at
4-
* http://mixxx.org/wiki/doku.php/components_js
4+
* https://github.com/mixxxdj/mixxx/wiki/Components-JS
55
*
66
* Copyright (C) 2017 Be <be.0@gmx.com>
77
*
@@ -18,12 +18,6 @@
1818
* You should have received a copy of the GNU General Public License
1919
* along with this program; if not, write to the Free Software
2020
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21-
*
22-
*
23-
*
24-
* This library depends on Lodash, which is copyright JS Foundation
25-
* and other contributors and licensed under the MIT license. Refer to
26-
* the lodash.mixxx.js file in this directory for details.
2721
*/
2822

2923
(function(global) {
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/**
2+
* Components JS library for Mixxx
3+
* Documentation is on the Mixxx wiki at
4+
* https://github.com/mixxxdj/mixxx/wiki/Components-JS
5+
*
6+
* Copyright (C) 2017 Be <be.0@gmx.com>
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License
10+
* as published by the Free Software Foundation; either version 2
11+
* of the License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21+
*/
22+
23+
(function(global) {
24+
/**
25+
* @typedef ComponentOpts
26+
* @property {number=} midiStatus
27+
* @property {number=} midiNo
28+
* @property {string=} group
29+
* @property {string=} inKey
30+
* @property {string=} outKey
31+
* @property {boolean} [outConnect=true]
32+
* @property {boolean} [outTrigger=true]
33+
* @property {number} [max=127]
34+
* @property {number} [shiftOffset=0]
35+
* @property {Component.SendShifted} [sendShifted=Component.SendShifted.NO]
36+
*/
37+
class Component {
38+
/**
39+
* @readonly
40+
* @enum {number}
41+
*/
42+
static SendShifted = Object.freeze({
43+
NO: 0,
44+
CHANNEL: 1,
45+
CONTROL: 2
46+
});
47+
48+
/** @type {ScriptConnection[]} */
49+
#connections = [];
50+
isShifted = false;
51+
52+
/** @param {(ComponentOpts|number[])} options */
53+
constructor(options) {
54+
if (Array.isArray(options)) {
55+
options = {midiStatus: options[0], midiNo: options[1]};
56+
}
57+
58+
/** type {ComponentOpts} */
59+
options = {
60+
midiStatus: undefined,
61+
midiNo: undefined,
62+
group: undefined,
63+
inKey: undefined,
64+
outKey: undefined,
65+
outConnect: true,
66+
outTrigger: true,
67+
max: 127,
68+
shiftOffset: 0,
69+
sendShifted: Component.SendShifted.NO,
70+
...options
71+
};
72+
73+
this.midiStatus = options.midiStatus;
74+
this.midiNo = options.midiNo;
75+
this.group = options.group;
76+
this.inKey = options.inKey;
77+
this.outKey = options.outKey;
78+
this.outConnect = options.outConnect;
79+
this.outTrigger = options.outTrigger;
80+
this.max = options.max;
81+
this.shiftOffset = options.shiftOffset;
82+
this.sendShifted = options.sendShifted;
83+
84+
if (this.outConnect) {
85+
this.connect();
86+
this.outTrigger ? this.trigger() : this.noop();
87+
}
88+
}
89+
90+
noop() { /* Does nothing */ }
91+
92+
inValueScale(value) {
93+
// Hack to get exact center of pots to return 0.5
94+
if (value > (this.max / 2)) {
95+
return (value - 1) / (this.max - 1);
96+
} else {
97+
return value / (this.max + 1);
98+
}
99+
}
100+
101+
/**
102+
* Processes a MIDI event received received from the HID/MIDI device
103+
*
104+
* By default, sets the Mixxx control {@link value} specified by {@link Component#inKey} in the group
105+
* {@link Component#group}.
106+
* @param {number} channel The MIDI channel
107+
* @param {number} control The MIDI control (MIDI data 2)
108+
* @param {number} value The MIDI value (MIDI byte 3)
109+
* @param {number} status The MIDI statut (MIDI byte 1, ex: 0x9n)
110+
* @param {string} group The Mixxx control group (ex: "[Master]")
111+
* {@see https://manual.mixxx.org/2.3/en/chapters/appendix/mixxx_controls.html}
112+
*/
113+
// eslint-disable-next-line no-unused-vars
114+
input(channel, control, value, status, group) {
115+
this.inSetParameter(this.inValueScale(value));
116+
}
117+
118+
outValueScale(value) {
119+
return value * this.max;
120+
}
121+
122+
/**
123+
* Processes a MIDI event specified by {@link Component#outKey} received from Mixxx in the group specified
124+
* by {@link Component#group}
125+
*
126+
* By default, forwards the value, transformed by {@link Component#outValueScale} to the HID/MIDI controller
127+
* using the MIDI status and MIDI group specified by {@link Component#midiStatus} and {@link Component#midiNo}
128+
* @param {number} value The MIDI value (MIDI byte 3)
129+
* @param {number} control The Mixxx control (Ex: play_indicator)
130+
* @param {string} group The Mixxx control group (ex: "[Channel1]")
131+
* {@see https://manual.mixxx.org/2.3/en/chapters/appendix/mixxx_controls.html}
132+
*/
133+
// eslint-disable-next-line no-unused-vars
134+
output(value, group, control) {
135+
this.send(this.outValueScale(value));
136+
}
137+
138+
// common functions
139+
// In most cases, you should not overwrite these.
140+
inGetParameter() {
141+
return engine.getParameter(this.group, this.inKey);
142+
}
143+
144+
inSetParameter(value) {
145+
engine.setParameter(this.group, this.inKey, value);
146+
}
147+
148+
inGetValue() {
149+
return engine.getValue(this.group, this.inKey);
150+
}
151+
152+
inSetValue(value) {
153+
engine.setValue(this.group, this.inKey, value);
154+
}
155+
156+
inToggle() {
157+
this.inSetValue(!this.inGetValue());
158+
}
159+
160+
outGetParameter() {
161+
return engine.getParameter(this.group, this.outKey);
162+
}
163+
164+
outSetParameter(value) {
165+
engine.setParameter(this.group, this.outKey, value);
166+
}
167+
168+
outGetValue() {
169+
return engine.getValue(this.group, this.outKey);
170+
}
171+
172+
outSetValue(value) {
173+
engine.setValue(this.group, this.outKey, value);
174+
}
175+
176+
outToggle() {
177+
this.outSetValue(!this.outGetValue());
178+
}
179+
180+
connect() {
181+
/**
182+
Override this method with a custom one to connect multiple Mixxx COs for a single Component.
183+
Add the connection objects to the this.connections array so they all get disconnected just
184+
by calling this.disconnect(). This can be helpful for multicolor LEDs that show a
185+
different color depending on the state of different Mixxx COs. Refer to
186+
SamplerButton.connect() and SamplerButton.output() for an example.
187+
*/
188+
if (this.group === undefined && this.outKey === undefined) {
189+
return;
190+
}
191+
192+
const connection = engine.makeConnection(this.group, this.outKey, this.output);
193+
if (connection !== undefined) {
194+
this.#connections.push(connection);
195+
}
196+
197+
}
198+
199+
disconnect() {
200+
this.#connections.forEach(it => it.disconnect());
201+
}
202+
203+
trigger() {
204+
this.#connections.forEach(it => it.trigger());
205+
}
206+
207+
send(value) {
208+
if (this.midiStatus === undefined || this.midiNo === undefined) {
209+
return;
210+
}
211+
212+
midi.sendShortMsg(this.midiStatus, this.midiNo, value);
213+
214+
if (this.sendShifted === Component.SendShifted.CHANNEL) {
215+
midi.sendShortMsg(this.midiStatus + this.shiftOffset, this.midiNo, value);
216+
} else if (this.sendShifted === Component.SendShifted.CONTROL) {
217+
midi.sendShortMsg(this.midiStatus, this.midiNo + this.shiftOffset, value);
218+
}
219+
}
220+
}
221+
222+
global.components = Object.freeze({
223+
Component
224+
});
225+
}(this));

0 commit comments

Comments
 (0)