WIP: beunsize map work
This commit is contained in:
parent
cad9433266
commit
4dd4db6f65
4 changed files with 153 additions and 8 deletions
|
|
@ -42,7 +42,7 @@ export class MidiControl<T extends MessageType> {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private device: MidiDevice,
|
private device: MidiDevice,
|
||||||
public type: MessageType,
|
public type: T,
|
||||||
private filter: Partial<DataLookup[T]>,
|
private filter: Partial<DataLookup[T]>,
|
||||||
private options: Partial<IMidiControlOptions> = {}
|
private options: Partial<IMidiControlOptions> = {}
|
||||||
|
|
||||||
|
|
@ -101,8 +101,17 @@ export class MidiControl<T extends MessageType> {
|
||||||
|
|
||||||
private feedback(data: DataLookup[T]) {
|
private feedback(data: DataLookup[T]) {
|
||||||
if (!this.device.output) console.log('midi device tried to send output without output device defined')
|
if (!this.device.output) console.log('midi device tried to send output without output device defined')
|
||||||
|
|
||||||
|
let type: MessageType = this.type;
|
||||||
|
|
||||||
|
if (this.type === MessageType.NoteOnOff) {
|
||||||
|
const rawData = data as NoteOnOffValue;
|
||||||
|
|
||||||
|
type = rawData.value ? MessageType.NoteOn : MessageType.NoteOff;
|
||||||
|
}
|
||||||
|
|
||||||
// ugly typing here, but library overloads are a little annoying to work around. worst case scenario nothing happens
|
// ugly typing here, but library overloads are a little annoying to work around. worst case scenario nothing happens
|
||||||
this.device.output?.send(this.type as any, { ...data, ...this.filter } as any);
|
this.device.output?.send(type as any, { ...data, ...this.filter } as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPage(): number { return this.page };
|
public getPage(): number { return this.page };
|
||||||
|
|
@ -147,9 +156,19 @@ export class MidiDevice {
|
||||||
|
|
||||||
public controls: Array<MidiControl<MessageType>> = [];
|
public controls: Array<MidiControl<MessageType>> = [];
|
||||||
|
|
||||||
constructor(inputDevice: string, outputDevice: string | boolean = false) {
|
constructor(inputDevice: string, outputDevice: string | boolean = false, virtual: boolean = false) {
|
||||||
if (outputDevice === true) outputDevice = inputDevice;
|
if (outputDevice === true) outputDevice = inputDevice;
|
||||||
|
|
||||||
|
if (virtual) {
|
||||||
|
this.input = new midi.Input(inputDevice, true)
|
||||||
|
|
||||||
|
if (outputDevice) {
|
||||||
|
this.output = new midi.Output(outputDevice, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
const inputDeviceFull = midi.getInputs().find(i => i.includes(inputDevice));
|
const inputDeviceFull = midi.getInputs().find(i => i.includes(inputDevice));
|
||||||
|
|
||||||
if (!inputDeviceFull) {
|
if (!inputDeviceFull) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import osc from "osc";
|
||||||
|
|
||||||
interface IOSCEvent {
|
interface IOSCEvent {
|
||||||
address: string;
|
address: string;
|
||||||
handler: (message: osc.ResponseMessage<osc.MessageArg>) => void;
|
handler: (message: osc.ResponseMessage<osc.MessageArg[]>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OSCDevice {
|
export class OSCDevice {
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,51 @@ import { mapNumber } from '../utilityFunctions.js'
|
||||||
|
|
||||||
export default async function mapping() {
|
export default async function mapping() {
|
||||||
|
|
||||||
const xtouch = new MidiDevice('X Touch Compact')
|
// DEVICES
|
||||||
|
|
||||||
|
const xtouch = new MidiDevice('X Touch Compact', true)
|
||||||
|
const xtouch_loop = new MidiDevice('XTouch-loop', true, true)
|
||||||
const keyboard = new MidiDevice('idobo')
|
const keyboard = new MidiDevice('idobo')
|
||||||
|
|
||||||
const ma3 = new OSCDevice('0.0.0.0', '127.0.0.1', 3000, 3001)
|
const ma3 = new OSCDevice('0.0.0.0', '127.0.0.1', 3000, 3001)
|
||||||
|
|
||||||
|
// UTILITY FUNCTIONS
|
||||||
|
|
||||||
|
const noteButtonFeedback = (note: number, address: string) => {
|
||||||
|
const button = xtouch.addControl(MessageType.NoteOnOff, { note });
|
||||||
|
|
||||||
|
ma3.addListener(address, message => {
|
||||||
|
const value = message.args[0]?.value
|
||||||
|
if (typeof value !== 'number') return;
|
||||||
|
|
||||||
|
button.handleFeedback(0, { value: value === 1 ? true : false })
|
||||||
|
})
|
||||||
|
|
||||||
|
button.addOutput(0, data => ma3.sendInt(address, data.value ? 1 : 0))
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ma3HardKey = (keycode: string, status: boolean) => {
|
||||||
|
ma3.sendString('/cmd', `Call Plugin "RBOSCKeys" "${keycode} ${status ? "press" : "release"}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MAPPINGS
|
||||||
|
|
||||||
|
// passthroughs for encoders plugin
|
||||||
|
[21, 22, 23, 24, 25, 26].forEach(encoder => {
|
||||||
|
xtouch.addControl(MessageType.CC, { controller: encoder }).addOutput(0, message => {
|
||||||
|
xtouch_loop.output?.send(MessageType.CC, message)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// Executor Faders
|
// Executor Faders
|
||||||
const faders = [0, 1, 2, 3, 4, 5, 6, 7, 8].map(f => xtouch.addControl(MessageType.CC, { controller: f }))
|
const faders = [0, 1, 2, 3, 4, 5, 6, 7, 8].map(f => xtouch.addControl(MessageType.CC, { controller: f }))
|
||||||
|
|
||||||
faders.forEach((fader, index) => {
|
faders.forEach((fader, index) => {
|
||||||
const firstExec = 201;
|
const firstExec = 201;
|
||||||
const exec = firstExec - 1 + index;
|
const exec = firstExec + index;
|
||||||
const address = `/Page/Fader${exec}`;
|
const address = `/Page/Fader${exec}`;
|
||||||
|
|
||||||
fader.addOutput(0, (message) => {
|
fader.addOutput(0, (message) => {
|
||||||
|
|
@ -31,13 +65,105 @@ export default async function mapping() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Executor Keys
|
||||||
const executorButtons: MidiControl<MessageType.NoteOnOff>[][] = [
|
const executorButtons: MidiControl<MessageType.NoteOnOff>[][] = [
|
||||||
[16, 17, 18, 19, 20, 21, 22, 23],
|
[16, 17, 18, 19, 20, 21, 22, 23],
|
||||||
[24, 25, 26, 27, 28, 29, 30, 31],
|
[24, 25, 26, 27, 28, 29, 30, 31],
|
||||||
[32, 33, 34, 35, 36, 37, 38, 39],
|
[32, 33, 34, 35, 36, 37, 38, 39],
|
||||||
[40, 41, 42, 43, 44, 45, 46, 47, 48],
|
[40, 41, 42, 43, 44, 45, 46, 47, 48],
|
||||||
].map(row => row.map(note => { xtouch.addControl(MessageType.NoteOnOff)))
|
].map((row, rowIndex) => row.map((note, noteIndex) => {
|
||||||
|
const rowLookup = [401, 301, 201, 101];
|
||||||
|
const address = `/Page/Key${rowLookup[rowIndex] ?? 101 + noteIndex}`
|
||||||
|
|
||||||
|
return noteButtonFeedback(note, address);
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
// Misc Buttons
|
||||||
|
const [rwd, fwd, loop, rec, stop, play] = [
|
||||||
|
{ note: 49, key: 'PAGE_UP' },
|
||||||
|
{ note: 50, key: 'PAGE_DOWN' },
|
||||||
|
{ note: 51, key: '' },
|
||||||
|
{ note: 52, key: '' },
|
||||||
|
{ note: 53, key: '' },
|
||||||
|
{ note: 53, key: '' },
|
||||||
|
]
|
||||||
|
.map(i => {
|
||||||
|
const button = xtouch.addControl(MessageType.NoteOnOff, { note: i.note })
|
||||||
|
button.addOutput(0, (message) => {
|
||||||
|
ma3HardKey(i.key, message.value)
|
||||||
|
})
|
||||||
|
return button
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Exec Encoders
|
||||||
|
|
||||||
|
const encoders = [11, 12, 13, 14, 15, 16, 17, 18].map((cc, index) => {
|
||||||
|
const encoder = xtouch.addControl(MessageType.CC, { controller: cc })
|
||||||
|
const firstExec = 401;
|
||||||
|
const address = `/Page/Encoder${firstExec + index}`;
|
||||||
|
const feedbackAddress = `/Page/Fader${firstExec + index}`;
|
||||||
|
|
||||||
|
encoder.addOutput(0, message => {
|
||||||
|
ma3.sendInt(address, mapNumber(message.value, 0, 1, -1, 1))
|
||||||
|
})
|
||||||
|
|
||||||
|
ma3.addListener(feedbackAddress, message => {
|
||||||
|
if (message.args[0] === undefined || message.args[0].type !== 'f') return;
|
||||||
|
const value = message.args[0].value;
|
||||||
|
|
||||||
|
encoder.handleFeedback(0, { value: mapNumber(value, 0, 1, 0, 127) })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// HARDKEYS
|
||||||
|
|
||||||
|
const keymap: string[][] = [
|
||||||
|
['pause', 'goback', 'go', 'fixture', 'channel', 'group', 'menu', 'oops', 'num7', 'num8', 'num9', 'plus', 'highlight', 'on', 'off'],
|
||||||
|
['learn', 'gobackfast', 'gofast', 'preset', 'sequence', 'cue', 'update', 'esc', 'num4', 'num5', 'num6', 'thru', 'solo', 'move', 'copy'],
|
||||||
|
['def_pause', 'def_goback', 'def_go', 'edit', 'assign', 'time', 'store', 'clear', 'num1', 'num2', 'num3', 'minus', 'freeze', 'delete', 'align'],
|
||||||
|
['x_1', 'x_2', 'x_3', 'x_4', 'x_5', 'x_6', 'x_7', 'x_8', 'num0', 'dot', 'if', 'at', 'preview', 'stomp', 'selfix'],
|
||||||
|
['x_9', 'x_10', 'x_11', 'x_13', 'x_14', 'x_15', 'x_16', 'previous', 'next', 'ma1', 'please', 'blind', 'select', 'goto']
|
||||||
|
]
|
||||||
|
|
||||||
|
const xkeymap: number[] =
|
||||||
|
[
|
||||||
|
291, 292, 293, 294, 295, 296, 297, 298,
|
||||||
|
191, 192, 193, 194, 195, 196, 197, 198
|
||||||
|
];
|
||||||
|
|
||||||
|
keymap.forEach((row, rowIndex) => {
|
||||||
|
row.forEach((key, keyIndex) => {
|
||||||
|
let totalIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (key.startsWith('x_')) {
|
||||||
|
const xKeyNum = parseInt(key.split('_')[1] ?? '0')
|
||||||
|
if (xKeyNum) {
|
||||||
|
const address = `/Page/Key${xkeymap[xKeyNum - 1]}`;
|
||||||
|
|
||||||
|
keyboard
|
||||||
|
.addControl(MessageType.CC, { controller: totalIndex })
|
||||||
|
.addOutput(0, message => {
|
||||||
|
ma3.sendInt(address, message.value ? 1 : 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
keyboard
|
||||||
|
.addControl(MessageType.CC, { controller: totalIndex })
|
||||||
|
.addOutput(0, message => {
|
||||||
|
ma3HardKey(key.toUpperCase(), message.value ? true : false);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
totalIndex++
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
2
src/types/osc/osc.d.ts
vendored
2
src/types/osc/osc.d.ts
vendored
|
|
@ -70,7 +70,7 @@ declare class OscEventsAndBase extends OscBase {
|
||||||
|
|
||||||
// On every time.
|
// On every time.
|
||||||
on(event: "ready", listener: OnListenerReady): void
|
on(event: "ready", listener: OnListenerReady): void
|
||||||
on<ARG_T = MessageArg>(
|
on<ARG_T = MessageArg[]>(
|
||||||
event: "message",
|
event: "message",
|
||||||
listener: OnListenerMessage<ARG_T>
|
listener: OnListenerMessage<ARG_T>
|
||||||
): void
|
): void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue