-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmidiControlMap.ts
More file actions
51 lines (46 loc) · 2.57 KB
/
Copy pathmidiControlMap.ts
File metadata and controls
51 lines (46 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Decoders for the GP-200's real-time footswitch / expression-pedal frames.
//
// STATUS: the exact wire format is PENDING a USB capture (see
// docs/protocol-capture.md §4, footswitch presses and EXP-pedal sweep). The
// cheapest hypothesis, consistent with the device exposing standard MIDI clock
// I/O, is that both arrive as **standard Control Change** messages rather than
// SysEx. This module implements that path with PLACEHOLDER CC numbers so the
// dispatcher and UI can be built and unit-tested now; swap the constants (and,
// if the capture shows SysEx instead, add a SysEx decoder here) once the
// `.pcap` diff lands. Keeping every magic number in this one pure module means
// the reverse-engineered format is documented, testable, and never smeared
// across the dispatcher.
//
// Evidence AGAINST the placeholder (2026-07-18): the device's documented
// incoming-CC surface (docs/protocol-capture.md §5, src/core/ccControl.ts)
// is command-oriented — CC69-72/76-79 are host→device "virtually tap
// CTRL1-8" commands — which makes it unlikely the device *emits* CC80-87 on
// hardware stomps. Stomps observed so far arrive as SysEx (looperTriggers.ts
// MIDI-learn handles them); expect the capture to retire FS_CC_MAP.
/** Foot-controller CC number carrying EXP-pedal position 0..127. PLACEHOLDER. */
export const EXP_CC = 4; // TODO(capture): confirm against gp200-exp-sweep.pcap
/** CC number → footswitch number (1..8). PLACEHOLDER mapping. */
export const FS_CC_MAP: ReadonlyMap<number, number> = new Map([
[80, 1], [81, 2], [82, 3], [83, 4],
[84, 5], [85, 6], [86, 7], [87, 8],
]); // TODO(capture): confirm against gp200-footswitch-*.pcap
/** CC value at/above which a footswitch counts as pressed (MIDI switch convention). */
export const FS_ON_THRESHOLD = 64;
export type ControlEvent =
| { kind: 'exp'; value: number } // 0..127
| { kind: 'footswitch'; fsNumber: number; state: boolean };
/**
* Decode an incoming raw MIDI message into a looper-relevant control event, or
* null if it isn't one. Handles standard Control Change (status 0xB0..0xBF);
* anything else (SysEx, notes) returns null and is left for other handlers.
*/
export function decodeControlChange(data: ArrayLike<number>): ControlEvent | null {
if (data.length < 3) return null;
if ((data[0] & 0xf0) !== 0xb0) return null; // not a Control Change
const cc = data[1];
const value = data[2];
if (cc === EXP_CC) return { kind: 'exp', value };
const fsNumber = FS_CC_MAP.get(cc);
if (fsNumber !== undefined) return { kind: 'footswitch', fsNumber, state: value >= FS_ON_THRESHOLD };
return null;
}