| author | |
| committer | |
| log | 86523418f2362aabae6d3729466100d9d200251b |
| tree | 488e6257b8e401446894bb08ad9d67c2aded1c09 |
| parent | 75da6a34d58d3ef23ff082a16a6252a61654565a |
| signature |
10 files changed, 373 insertions(+), 305 deletions(-)
config/reaper.ts+68-52| ... | ... | @@ -1,58 +1,74 @@ |
| 1 | import * as config from "#config"; | |
| 1 | 2 | import { Reaper } from "@clo/creative-control/Reaper.ts"; |
| 2 | 3 | import { SpeedEditor } from "@clo/creative-control/SpeedEditor.ts"; |
| 3 | import * as config from "#config"; | |
| 4 | 4 | |
| 5 | export default config.forApp("com.cockos.reaper", ({ speededitor: se, mac }) => { | |
| 6 | const reaper = new Reaper(); | |
| 5 | export default config.forApp( | |
| 6 | "com.cockos.reaper", | |
| 7 | ({ speededitor: se, mac }) => { | |
| 8 | const reaper = new Reaper(); | |
| 7 | 9 | |
| 8 | // Sync state to LEDs | |
| 9 | reaper.on("transport", (transport) => { | |
| 10 | console.info(transport); | |
| 11 | se.leds.audioOnly = transport.recording; | |
| 12 | }); | |
| 13 | mac.on("window", (window) => { | |
| 14 | se.leds.videoOnly = Boolean(window?.title.startsWith("FX:")); | |
| 15 | }); | |
| 10 | // Sync state to LEDs | |
| 11 | reaper.on("transport", (transport) => { | |
| 12 | se.leds.cut = transport.recording; | |
| 13 | se.leds.dissolve = transport.recording; | |
| 14 | se.leds.smoothCut = transport.recording; | |
| 15 | }); | |
| 16 | mac.on("window", (window) => { | |
| 17 | se.leds.videoOnly = Boolean(window?.title.startsWith("FX:")); | |
| 18 | }); | |
| 16 | 19 | |
| 17 | // Keyboard Actions | |
| 18 | SpeedEditor.camNumbersToNumpad(se, mac); | |
| 19 | se.onPress("stopPlay", () => { | |
| 20 | if(reaper.transport.recording) { | |
| 21 | reaper.runAction('transport-stop-save-all-recorded-media'); | |
| 22 | } else { | |
| 23 | reaper.runAction('transport-play-stop'); | |
| 24 | } | |
| 25 | }); | |
| 26 | se.onPress("smartInsert", () => { | |
| 27 | mac.toast("Add Komplete Kontrol") | |
| 28 | reaper.runScript("insert_komplete_kontrol_track"); | |
| 29 | }); | |
| 30 | se.onPress("append", () => { | |
| 31 | mac.toast("Add Addictive Drums") | |
| 32 | reaper.runScript("insert_addictive_drums_track"); | |
| 33 | }); | |
| 34 | se.onPress("rippleOverwrite", () => { | |
| 35 | mac.toast("Blank Track") | |
| 36 | reaper.runScript("insert_blank_track"); | |
| 37 | }); | |
| 38 | se.onPress("audioOnly", () => { | |
| 39 | if(reaper.transport.recording) { | |
| 40 | reaper.runAction('transport-stop-delete-all-recorded-media'); | |
| 41 | reaper.runAction('transport-record'); | |
| 42 | } else { | |
| 43 | reaper.runAction('transport-record'); | |
| 44 | } | |
| 45 | }); | |
| 46 | se.onPress("videoOnly", () => { | |
| 47 | if (mac.window?.title.startsWith("FX:") && mac.mainWindow) { | |
| 48 | mac.focusMainWindow(); | |
| 49 | return; | |
| 50 | } | |
| 51 | reaper.runAction("track-view-fx-chain-for-current-last-touched-track"); | |
| 52 | }); | |
| 20 | // Keyboard Actions | |
| 21 | SpeedEditor.camNumbersToNumpad(se, mac); | |
| 22 | se.onPress("stopPlay", () => { | |
| 23 | if (reaper.transport.recording) { | |
| 24 | reaper.runAction("transport-stop-save-all-recorded-media"); | |
| 25 | } else { | |
| 26 | reaper.runAction("transport-play-stop"); | |
| 27 | } | |
| 28 | }); | |
| 29 | se.onPress("smartInsert", () => { | |
| 30 | mac.toast("Add Komplete Kontrol"); | |
| 31 | reaper.runScript("insert_komplete_kontrol_track"); | |
| 32 | }); | |
| 33 | se.onPress("append", () => { | |
| 34 | mac.toast("Add Addictive Drums"); | |
| 35 | reaper.runScript("insert_addictive_drums_track"); | |
| 36 | }); | |
| 37 | se.onPress("rippleOverwrite", () => { | |
| 38 | mac.toast("Blank Track"); | |
| 39 | reaper.runScript("insert_blank_track"); | |
| 40 | }); | |
| 41 | se.onPress("cut", () => { | |
| 42 | if (reaper.transport.recording) { | |
| 43 | reaper.runAction("transport-stop-delete-all-recorded-media"); | |
| 44 | reaper.runAction("transport-record"); | |
| 45 | } else { | |
| 46 | reaper.runAction("transport-record"); | |
| 47 | } | |
| 48 | }); | |
| 49 | se.onPress("dissolve", () => { | |
| 50 | reaper.runAction("transport-stop-delete-all-recorded-media"); | |
| 51 | }); | |
| 52 | se.onPress("smoothCut", () => { | |
| 53 | if (reaper.transport.recording) { | |
| 54 | reaper.runAction("transport-stop-save-all-recorded-media"); | |
| 55 | reaper.runAction("transport-record"); | |
| 56 | } | |
| 57 | }); | |
| 58 | se.onPress("videoOnly", () => { | |
| 59 | if (mac.window?.title.startsWith("FX:") && mac.mainWindow) { | |
| 60 | mac.focusMainWindow(); | |
| 61 | return; | |
| 62 | } | |
| 63 | reaper.runAction("track-view-fx-chain-for-current-last-touched-track"); | |
| 64 | }); | |
| 65 | se.onPress("fullView", () => { | |
| 66 | mac.pressKey("x"); | |
| 67 | }); | |
| 53 | 68 | |
| 54 | // TODO: stabilize / find a better use-case for the knob | |
| 55 | se.on("jog", ({ value = 0 }) => { | |
| 56 | reaper.scrub(value / 20); | |
| 57 | }); | |
| 58 | }); | |
| 69 | // TODO: stabilize / find a better use-case for the knob | |
| 70 | // se.on("jog", ({ value = 0 }) => { | |
| 71 | // reaper.scrub(value / 20); | |
| 72 | // }); | |
| 73 | }, | |
| 74 | ); |
dprint.json created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | { | |
| 2 | "typescript": { | |
| 3 | }, | |
| 4 | "json": { | |
| 5 | }, | |
| 6 | "markdown": { | |
| 7 | }, | |
| 8 | "excludes": [ | |
| 9 | "**/node_modules", | |
| 10 | "**/*-lock.json" | |
| 11 | ], | |
| 12 | "plugins": [ | |
| 13 | "https://plugins.dprint.dev/typescript-0.95.15.wasm", | |
| 14 | "https://plugins.dprint.dev/json-0.21.1.wasm", | |
| 15 | "https://plugins.dprint.dev/markdown-0.21.1.wasm" | |
| 16 | ] | |
| 17 | } |
examples/event-listener.ts+1-1| ... | ... | @@ -15,7 +15,7 @@ editor.on("keypress", (key) => { |
| 15 | 15 | } |
| 16 | 16 | }); |
| 17 | 17 | editor.onDoublePress("transition", () => { |
| 18 | console.info('(double press) "Title"'); | |
| 18 | console.info("(double press) \"Title\""); | |
| 19 | 19 | }); |
| 20 | 20 | |
| 21 | 21 | console.info("init"); |
readme.md+4-3| ... | ... | @@ -10,7 +10,8 @@ These tools only work on macOS. I don't have interest in maintaining other confi |
| 10 | 10 | |
| 11 | 11 | ## Hardware |
| 12 | 12 | |
| 13 | TODO: | |
| 13 | TODO: | |
| 14 | ||
| 14 | 15 | - generic keyboard / karabiner elements integration? |
| 15 | 16 | - custom trackpad integration? |
| 16 | 17 | |
| ... | ... | @@ -55,8 +56,8 @@ reaper.on("transport", (transport) => { |
| 55 | 56 | transport.recording |
| 56 | 57 | ? "You are recording" |
| 57 | 58 | : transport.playing |
| 58 | ? "Playing" | |
| 59 | : "Stopped" | |
| 59 | ? "Playing" | |
| 60 | : "Stopped", | |
| 60 | 61 | ); |
| 61 | 62 | }); |
| 62 | 63 | ``` |
src/Mac.ts+142-140| ... | ... | @@ -32,13 +32,13 @@ const FRONTMOST_APP_HELPER_FRAMEWORKS = [ |
| 32 | 32 | "ApplicationServices", |
| 33 | 33 | ] as const; |
| 34 | 34 | const KEYBOARD_EVENT_SCRIPT = [ |
| 35 | 'ObjC.import("ApplicationServices");', | |
| 35 | "ObjC.import(\"ApplicationServices\");", | |
| 36 | 36 | "function run(argv) {", |
| 37 | 37 | " const payload = JSON.parse(argv[0] ?? '{}');", |
| 38 | 38 | " const actions = Array.isArray(payload.actions) ? payload.actions : [];", |
| 39 | 39 | " for (const action of actions) {", |
| 40 | 40 | " if (!Number.isInteger(action.keyCode)) {", |
| 41 | ' throw new Error(`Invalid key code: ${JSON.stringify(action)}`);', | |
| 41 | " throw new Error(`Invalid key code: ${JSON.stringify(action)}`);", | |
| 42 | 42 | " }", |
| 43 | 43 | " const event = $.CGEventCreateKeyboardEvent(", |
| 44 | 44 | " null,", |
| ... | ... | @@ -46,139 +46,141 @@ const KEYBOARD_EVENT_SCRIPT = [ |
| 46 | 46 | " Boolean(action.isDown),", |
| 47 | 47 | " );", |
| 48 | 48 | " if (!event) {", |
| 49 | ' throw new Error(`Failed to create keyboard event for key code ${action.keyCode}`);', | |
| 49 | " throw new Error(`Failed to create keyboard event for key code ${action.keyCode}`);", | |
| 50 | 50 | " }", |
| 51 | 51 | " $.CGEventPost($.kCGHIDEventTap, event);", |
| 52 | 52 | " $.CFRelease(event);", |
| 53 | 53 | " }", |
| 54 | ' return "";', | |
| 54 | " return \"\";", | |
| 55 | 55 | "}", |
| 56 | 56 | ].join("\n"); |
| 57 | 57 | let frontmostAppHelperBinaryPromise: Promise<string> | null = null; |
| 58 | 58 | let toastHelperBinaryPromise: Promise<string> | null = null; |
| 59 | 59 | |
| 60 | 60 | // Key codes from Carbon/HIToolbox Events.h (virtual key codes on ANSI/US layouts). |
| 61 | const KEY_CODES = Object.freeze({ | |
| 62 | a: 0x00, | |
| 63 | s: 0x01, | |
| 64 | d: 0x02, | |
| 65 | f: 0x03, | |
| 66 | h: 0x04, | |
| 67 | g: 0x05, | |
| 68 | z: 0x06, | |
| 69 | x: 0x07, | |
| 70 | c: 0x08, | |
| 71 | v: 0x09, | |
| 72 | isoSection: 0x0A, | |
| 73 | b: 0x0B, | |
| 74 | q: 0x0C, | |
| 75 | w: 0x0D, | |
| 76 | e: 0x0E, | |
| 77 | r: 0x0F, | |
| 78 | y: 0x10, | |
| 79 | t: 0x11, | |
| 80 | "1": 0x12, | |
| 81 | "2": 0x13, | |
| 82 | "3": 0x14, | |
| 83 | "4": 0x15, | |
| 84 | "6": 0x16, | |
| 85 | "5": 0x17, | |
| 86 | equal: 0x18, | |
| 87 | "9": 0x19, | |
| 88 | "7": 0x1A, | |
| 89 | minus: 0x1B, | |
| 90 | "8": 0x1C, | |
| 91 | "0": 0x1D, | |
| 92 | rightBracket: 0x1E, | |
| 93 | o: 0x1F, | |
| 94 | u: 0x20, | |
| 95 | leftBracket: 0x21, | |
| 96 | i: 0x22, | |
| 97 | p: 0x23, | |
| 98 | return: 0x24, | |
| 99 | l: 0x25, | |
| 100 | j: 0x26, | |
| 101 | quote: 0x27, | |
| 102 | k: 0x28, | |
| 103 | semicolon: 0x29, | |
| 104 | backslash: 0x2A, | |
| 105 | comma: 0x2B, | |
| 106 | slash: 0x2C, | |
| 107 | n: 0x2D, | |
| 108 | m: 0x2E, | |
| 109 | period: 0x2F, | |
| 110 | tab: 0x30, | |
| 111 | space: 0x31, | |
| 112 | grave: 0x32, | |
| 113 | delete: 0x33, | |
| 114 | escape: 0x35, | |
| 115 | rightCommand: 0x36, | |
| 116 | command: 0x37, | |
| 117 | shift: 0x38, | |
| 118 | capsLock: 0x39, | |
| 119 | option: 0x3A, | |
| 120 | control: 0x3B, | |
| 121 | rightShift: 0x3C, | |
| 122 | rightOption: 0x3D, | |
| 123 | rightControl: 0x3E, | |
| 124 | function: 0x3F, | |
| 125 | f17: 0x40, | |
| 126 | numpadDecimal: 0x41, | |
| 127 | numpadMultiply: 0x43, | |
| 128 | numpadPlus: 0x45, | |
| 129 | numpadClear: 0x47, | |
| 130 | volumeUp: 0x48, | |
| 131 | volumeDown: 0x49, | |
| 132 | mute: 0x4A, | |
| 133 | numpadDivide: 0x4B, | |
| 134 | numpadEnter: 0x4C, | |
| 135 | numpadMinus: 0x4E, | |
| 136 | f18: 0x4F, | |
| 137 | f19: 0x50, | |
| 138 | numpadEquals: 0x51, | |
| 139 | numpad0: 0x52, | |
| 140 | numpad1: 0x53, | |
| 141 | numpad2: 0x54, | |
| 142 | numpad3: 0x55, | |
| 143 | numpad4: 0x56, | |
| 144 | numpad5: 0x57, | |
| 145 | numpad6: 0x58, | |
| 146 | numpad7: 0x59, | |
| 147 | f20: 0x5A, | |
| 148 | numpad8: 0x5B, | |
| 149 | numpad9: 0x5C, | |
| 150 | jisYen: 0x5D, | |
| 151 | jisUnderscore: 0x5E, | |
| 152 | jisKeypadComma: 0x5F, | |
| 153 | f5: 0x60, | |
| 154 | f6: 0x61, | |
| 155 | f7: 0x62, | |
| 156 | f3: 0x63, | |
| 157 | f8: 0x64, | |
| 158 | f9: 0x65, | |
| 159 | jisEisu: 0x66, | |
| 160 | f11: 0x67, | |
| 161 | jisKana: 0x68, | |
| 162 | f13: 0x69, | |
| 163 | f16: 0x6A, | |
| 164 | f14: 0x6B, | |
| 165 | f10: 0x6D, | |
| 166 | f12: 0x6F, | |
| 167 | f15: 0x71, | |
| 168 | help: 0x72, | |
| 169 | home: 0x73, | |
| 170 | pageUp: 0x74, | |
| 171 | forwardDelete: 0x75, | |
| 172 | f4: 0x76, | |
| 173 | end: 0x77, | |
| 174 | f2: 0x78, | |
| 175 | pageDown: 0x79, | |
| 176 | f1: 0x7A, | |
| 177 | leftArrow: 0x7B, | |
| 178 | rightArrow: 0x7C, | |
| 179 | downArrow: 0x7D, | |
| 180 | upArrow: 0x7E, | |
| 181 | } as const); | |
| 61 | const KEY_CODES = Object.freeze( | |
| 62 | { | |
| 63 | a: 0x00, | |
| 64 | s: 0x01, | |
| 65 | d: 0x02, | |
| 66 | f: 0x03, | |
| 67 | h: 0x04, | |
| 68 | g: 0x05, | |
| 69 | z: 0x06, | |
| 70 | x: 0x07, | |
| 71 | c: 0x08, | |
| 72 | v: 0x09, | |
| 73 | isoSection: 0x0A, | |
| 74 | b: 0x0B, | |
| 75 | q: 0x0C, | |
| 76 | w: 0x0D, | |
| 77 | e: 0x0E, | |
| 78 | r: 0x0F, | |
| 79 | y: 0x10, | |
| 80 | t: 0x11, | |
| 81 | "1": 0x12, | |
| 82 | "2": 0x13, | |
| 83 | "3": 0x14, | |
| 84 | "4": 0x15, | |
| 85 | "6": 0x16, | |
| 86 | "5": 0x17, | |
| 87 | equal: 0x18, | |
| 88 | "9": 0x19, | |
| 89 | "7": 0x1A, | |
| 90 | minus: 0x1B, | |
| 91 | "8": 0x1C, | |
| 92 | "0": 0x1D, | |
| 93 | rightBracket: 0x1E, | |
| 94 | o: 0x1F, | |
| 95 | u: 0x20, | |
| 96 | leftBracket: 0x21, | |
| 97 | i: 0x22, | |
| 98 | p: 0x23, | |
| 99 | return: 0x24, | |
| 100 | l: 0x25, | |
| 101 | j: 0x26, | |
| 102 | quote: 0x27, | |
| 103 | k: 0x28, | |
| 104 | semicolon: 0x29, | |
| 105 | backslash: 0x2A, | |
| 106 | comma: 0x2B, | |
| 107 | slash: 0x2C, | |
| 108 | n: 0x2D, | |
| 109 | m: 0x2E, | |
| 110 | period: 0x2F, | |
| 111 | tab: 0x30, | |
| 112 | space: 0x31, | |
| 113 | grave: 0x32, | |
| 114 | delete: 0x33, | |
| 115 | escape: 0x35, | |
| 116 | rightCommand: 0x36, | |
| 117 | command: 0x37, | |
| 118 | shift: 0x38, | |
| 119 | capsLock: 0x39, | |
| 120 | option: 0x3A, | |
| 121 | control: 0x3B, | |
| 122 | rightShift: 0x3C, | |
| 123 | rightOption: 0x3D, | |
| 124 | rightControl: 0x3E, | |
| 125 | function: 0x3F, | |
| 126 | f17: 0x40, | |
| 127 | numpadDecimal: 0x41, | |
| 128 | numpadMultiply: 0x43, | |
| 129 | numpadPlus: 0x45, | |
| 130 | numpadClear: 0x47, | |
| 131 | volumeUp: 0x48, | |
| 132 | volumeDown: 0x49, | |
| 133 | mute: 0x4A, | |
| 134 | numpadDivide: 0x4B, | |
| 135 | numpadEnter: 0x4C, | |
| 136 | numpadMinus: 0x4E, | |
| 137 | f18: 0x4F, | |
| 138 | f19: 0x50, | |
| 139 | numpadEquals: 0x51, | |
| 140 | numpad0: 0x52, | |
| 141 | numpad1: 0x53, | |
| 142 | numpad2: 0x54, | |
| 143 | numpad3: 0x55, | |
| 144 | numpad4: 0x56, | |
| 145 | numpad5: 0x57, | |
| 146 | numpad6: 0x58, | |
| 147 | numpad7: 0x59, | |
| 148 | f20: 0x5A, | |
| 149 | numpad8: 0x5B, | |
| 150 | numpad9: 0x5C, | |
| 151 | jisYen: 0x5D, | |
| 152 | jisUnderscore: 0x5E, | |
| 153 | jisKeypadComma: 0x5F, | |
| 154 | f5: 0x60, | |
| 155 | f6: 0x61, | |
| 156 | f7: 0x62, | |
| 157 | f3: 0x63, | |
| 158 | f8: 0x64, | |
| 159 | f9: 0x65, | |
| 160 | jisEisu: 0x66, | |
| 161 | f11: 0x67, | |
| 162 | jisKana: 0x68, | |
| 163 | f13: 0x69, | |
| 164 | f16: 0x6A, | |
| 165 | f14: 0x6B, | |
| 166 | f10: 0x6D, | |
| 167 | f12: 0x6F, | |
| 168 | f15: 0x71, | |
| 169 | help: 0x72, | |
| 170 | home: 0x73, | |
| 171 | pageUp: 0x74, | |
| 172 | forwardDelete: 0x75, | |
| 173 | f4: 0x76, | |
| 174 | end: 0x77, | |
| 175 | f2: 0x78, | |
| 176 | pageDown: 0x79, | |
| 177 | f1: 0x7A, | |
| 178 | leftArrow: 0x7B, | |
| 179 | rightArrow: 0x7C, | |
| 180 | downArrow: 0x7D, | |
| 181 | upArrow: 0x7E, | |
| 182 | } as const, | |
| 183 | ); | |
| 182 | 184 | type MacKeyName = keyof typeof KEY_CODES; |
| 183 | 185 | |
| 184 | 186 | const KEY_NAMES = Object.freeze(Object.keys(KEY_CODES) as MacKeyName[]); |
| ... | ... | @@ -732,12 +734,12 @@ function parseFrontmostStateLine(line: string): FrontmostState { |
| 732 | 734 | |
| 733 | 735 | function normalizeBundleId(value: unknown) { |
| 734 | 736 | const directBundleId = typeof value === "string" ? value.trim() : ""; |
| 735 | const bundleId = BUNDLE_ID_PATTERN.exec(directBundleId)?.[0] ?? | |
| 736 | directBundleId; | |
| 737 | const bundleId = BUNDLE_ID_PATTERN.exec(directBundleId)?.[0] | |
| 738 | ?? directBundleId; | |
| 737 | 739 | if ( |
| 738 | bundleId === "" || | |
| 739 | bundleId === "undefined" || | |
| 740 | bundleId === "[id nil]" | |
| 740 | bundleId === "" | |
| 741 | || bundleId === "undefined" | |
| 742 | || bundleId === "[id nil]" | |
| 741 | 743 | ) { |
| 742 | 744 | return null; |
| 743 | 745 | } |
| ... | ... | @@ -837,10 +839,10 @@ function windowEquals(left: Mac.Window | null, right: Mac.Window | null) { |
| 837 | 839 | if (!left || !right) { |
| 838 | 840 | return left === right; |
| 839 | 841 | } |
| 840 | return left.id === right.id && | |
| 841 | left.title === right.title && | |
| 842 | left.main === right.main && | |
| 843 | left.focused === right.focused; | |
| 842 | return left.id === right.id | |
| 843 | && left.title === right.title | |
| 844 | && left.main === right.main | |
| 845 | && left.focused === right.focused; | |
| 844 | 846 | } |
| 845 | 847 | |
| 846 | 848 | function normalizeDelayMs(value: number, name: string) { |
| ... | ... | @@ -884,9 +886,9 @@ function resolveKeyCode(key: Mac.Key): number { |
| 884 | 886 | |
| 885 | 887 | function normalizeKeyCode(keyCode: number) { |
| 886 | 888 | if ( |
| 887 | !Number.isInteger(keyCode) || | |
| 888 | keyCode < 0 || | |
| 889 | keyCode > 0xFFFF | |
| 889 | !Number.isInteger(keyCode) | |
| 890 | || keyCode < 0 | |
| 891 | || keyCode > 0xFFFF | |
| 890 | 892 | ) { |
| 891 | 893 | throw new Error(`Mac keyCode must be an integer between 0 and 65535`); |
| 892 | 894 | } |
| ... | ... | @@ -946,9 +948,9 @@ function formatKeyboardDispatchError(error: unknown) { |
| 946 | 948 | const details = extractCommandErrorOutput(error); |
| 947 | 949 | const suffix = details ? ` ${details}` : ""; |
| 948 | 950 | return ( |
| 949 | "Failed to send a macOS keyboard event via osascript. " + | |
| 950 | "Make sure this process is allowed in System Settings > Privacy & Security > Accessibility." + | |
| 951 | suffix | |
| 951 | "Failed to send a macOS keyboard event via osascript. " | |
| 952 | + "Make sure this process is allowed in System Settings > Privacy & Security > Accessibility." | |
| 953 | + suffix | |
| 952 | 954 | ); |
| 953 | 955 | } |
| 954 | 956 |
src/Reaper.ts+20-20| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | import { Events } from "@clo/lib/Events.ts"; |
| 2 | 2 | import * as log from "@clo/lib/log.ts"; |
| 3 | import { REAPER_ACTIONS, type ReaperActionId } from "./Reaper/actions.ts"; | |
| 4 | 3 | import { execFile } from "node:child_process"; |
| 5 | 4 | import { createSocket, type Socket } from "node:dgram"; |
| 6 | 5 | import { readFileSync } from "node:fs"; |
| ... | ... | @@ -9,6 +8,7 @@ import { basename, dirname, join } from "node:path"; |
| 9 | 8 | import process from "node:process"; |
| 10 | 9 | import { fileURLToPath } from "node:url"; |
| 11 | 10 | import { promisify } from "node:util"; |
| 11 | import { REAPER_ACTIONS, type ReaperActionId } from "./Reaper/actions.ts"; | |
| 12 | 12 | const console = log.scoped("reaper"); |
| 13 | 13 | |
| 14 | 14 | export type { ReaperActionId } from "./Reaper/actions.ts"; |
| ... | ... | @@ -94,10 +94,10 @@ const DEFAULT_REAPER_OSC_TARGET_DIR = join( |
| 94 | 94 | DEFAULT_REAPER_RESOURCE_DIR, |
| 95 | 95 | "OSC", |
| 96 | 96 | ); |
| 97 | const REAPER_SCRIPT_TARGET_DIR = process.env.REAPER_SCRIPTS_DIR ?? | |
| 98 | DEFAULT_REAPER_SCRIPT_TARGET_DIR; | |
| 99 | const REAPER_OSC_TARGET_DIR = process.env.REAPER_OSC_DIR ?? | |
| 100 | DEFAULT_REAPER_OSC_TARGET_DIR; | |
| 97 | const REAPER_SCRIPT_TARGET_DIR = process.env.REAPER_SCRIPTS_DIR | |
| 98 | ?? DEFAULT_REAPER_SCRIPT_TARGET_DIR; | |
| 99 | const REAPER_OSC_TARGET_DIR = process.env.REAPER_OSC_DIR | |
| 100 | ?? DEFAULT_REAPER_OSC_TARGET_DIR; | |
| 101 | 101 | const OSC_PATTERN_FILE = "CloverAutomation.ReaperOSC"; |
| 102 | 102 | const OSC_PATTERN_NAME = stripReaperOscExtension(OSC_PATTERN_FILE); |
| 103 | 103 | const OSC_PATTERN_CONFIG = `# OSC pattern config file for Clover Creative Control's REAPER integration. |
| ... | ... | @@ -174,10 +174,10 @@ export class Reaper extends Events<Reaper.EventMap> { |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | 176 | console.info( |
| 177 | `${OSC_PATTERN_FILE} is not registered yet. ` + | |
| 178 | `Add an OSC control surface manually using the "${OSC_PATTERN_NAME}" pattern, set REAPER's local listen port to ` + | |
| 179 | `${this.#oscPort}, and send to ${this.#oscHost}:${this.#oscBindPort}. ` + | |
| 180 | "The REAPER web interface is not required for this config." | |
| 177 | `${OSC_PATTERN_FILE} is not registered yet. ` | |
| 178 | + `Add an OSC control surface manually using the "${OSC_PATTERN_NAME}" pattern, set REAPER's local listen port to ` | |
| 179 | + `${this.#oscPort}, and send to ${this.#oscHost}:${this.#oscBindPort}. ` | |
| 180 | + "The REAPER web interface is not required for this config.", | |
| 181 | 181 | ); |
| 182 | 182 | } |
| 183 | 183 | |
| ... | ... | @@ -475,13 +475,13 @@ function sameTransportState( |
| 475 | 475 | left: ReaperTransportState, |
| 476 | 476 | right: ReaperTransportState, |
| 477 | 477 | ) { |
| 478 | return left.playing === right.playing && | |
| 479 | left.paused === right.paused && | |
| 480 | left.recording === right.recording && | |
| 481 | left.repeatOn === right.repeatOn && | |
| 482 | left.positionSeconds === right.positionSeconds && | |
| 483 | left.positionString === right.positionString && | |
| 484 | left.positionBeatsString === right.positionBeatsString; | |
| 478 | return left.playing === right.playing | |
| 479 | && left.paused === right.paused | |
| 480 | && left.recording === right.recording | |
| 481 | && left.repeatOn === right.repeatOn | |
| 482 | && left.positionSeconds === right.positionSeconds | |
| 483 | && left.positionString === right.positionString | |
| 484 | && left.positionBeatsString === right.positionBeatsString; | |
| 485 | 485 | } |
| 486 | 486 | |
| 487 | 487 | function optimisticTransportPatchForAction( |
| ... | ... | @@ -615,8 +615,8 @@ function hasManagedOscSurface(config: string) { |
| 615 | 615 | |
| 616 | 616 | const normalizedTokens = tokens.map((token) => unquoteReaperToken(token)); |
| 617 | 617 | if ( |
| 618 | normalizedTokens.includes(OSC_PATTERN_FILE) || | |
| 619 | normalizedTokens.includes(OSC_PATTERN_NAME) | |
| 618 | normalizedTokens.includes(OSC_PATTERN_FILE) | |
| 619 | || normalizedTokens.includes(OSC_PATTERN_NAME) | |
| 620 | 620 | ) { |
| 621 | 621 | return true; |
| 622 | 622 | } |
| ... | ... | @@ -645,8 +645,8 @@ function formatError(error: unknown) { |
| 645 | 645 | |
| 646 | 646 | function unquoteReaperToken(token: string) { |
| 647 | 647 | if ( |
| 648 | (token.startsWith("'") && token.endsWith("'")) || | |
| 649 | (token.startsWith("\"") && token.endsWith("\"")) | |
| 648 | (token.startsWith("'") && token.endsWith("'")) | |
| 649 | || (token.startsWith("\"") && token.endsWith("\"")) | |
| 650 | 650 | ) { |
| 651 | 651 | return token.slice(1, -1); |
| 652 | 652 | } |
src/Reaper/actions.ts+82-41| ... | ... | @@ -52,7 +52,8 @@ export const REAPER_ACTIONS = { |
| 52 | 52 | "action-skip-next-action-if-cc-parameter-0-mid-2017": 2017, |
| 53 | 53 | "action-skip-next-action-if-cc-parameter-0-mid-2018": 2018, |
| 54 | 54 | "action-skip-next-action-set-cc-parameter-to-relative-plus-1-if-action-armed-0-otherwise": 2023, |
| 55 | "action-skip-next-action-set-cc-parameter-to-relative-plus-1-if-action-toggle-state-enabled-1-if-disabled-0-if-toggle-state-unavailable": 2022, | |
| 55 | "action-skip-next-action-set-cc-parameter-to-relative-plus-1-if-action-toggle-state-enabled-1-if-disabled-0-if-toggle-state-unavailable": | |
| 56 | 2022, | |
| 56 | 57 | "action-toggle-arm-of-next-action": 2021, |
| 57 | 58 | "action-wait-0-1-seconds-before-next-action": 2008, |
| 58 | 59 | "action-wait-0-5-seconds-before-next-action": 2009, |
| ... | ... | @@ -625,7 +626,8 @@ export const REAPER_ACTIONS = { |
| 625 | 626 | "file-open-render-queue": 40929, |
| 626 | 627 | "file-open-render-statistics-charts-from-most-recent-render-in-web-browser": 42497, |
| 627 | 628 | "file-open-render-statistics-charts-from-most-recent-render-in-web-browser-hide-file-paths": 42510, |
| 628 | "file-open-render-statistics-charts-from-most-recent-render-in-web-browser-hide-file-paths-and-project-regions-markers": 43343, | |
| 629 | "file-open-render-statistics-charts-from-most-recent-render-in-web-browser-hide-file-paths-and-project-regions-markers": | |
| 630 | 43343, | |
| 629 | 631 | "file-open-render-statistics-charts-from-most-recent-render-in-web-browser-hide-project-regions-markers": 43342, |
| 630 | 632 | "file-project-settings": 40021, |
| 631 | 633 | "file-quit-reaper": 40004, |
| ... | ... | @@ -1203,7 +1205,8 @@ export const REAPER_ACTIONS = { |
| 1203 | 1205 | "item-open-items-in-secondary-external-editor": 40202, |
| 1204 | 1206 | "item-paste-items-tracks": 42398, |
| 1205 | 1207 | "item-paste-items-tracks-at-mouse-position": 41221, |
| 1206 | "item-paste-items-tracks-creating-pooled-ghost-midi-items-and-automation-items-regardless-of-preferences-media-midi-and-preferences-media-automation-settings": 41072, | |
| 1208 | "item-paste-items-tracks-creating-pooled-ghost-midi-items-and-automation-items-regardless-of-preferences-media-midi-and-preferences-media-automation-settings": | |
| 1209 | 41072, | |
| 1207 | 1210 | "item-paste-items-tracks-old-style-handling-of-hidden-tracks": 40058, |
| 1208 | 1211 | "item-propagate-to-all-similarly-named-items": 41979, |
| 1209 | 1212 | "item-propagate-to-similarly-named-items-on-track": 41977, |
| ... | ... | @@ -1256,9 +1259,12 @@ export const REAPER_ACTIONS = { |
| 1256 | 1259 | "item-properties-set-item-timebase-to-beats-position-only": 40485, |
| 1257 | 1260 | "item-properties-set-item-timebase-to-project-track-default": 40380, |
| 1258 | 1261 | "item-properties-set-item-timebase-to-time": 40433, |
| 1259 | "item-properties-set-midi-items-to-follow-project-tempo-changes-set-item-timebase-to-beats-position-length-rate": 43095, | |
| 1260 | "item-properties-set-midi-items-to-use-current-tempo-and-ignore-project-tempo-changes-set-item-timebase-to-beats-position-only": 43096, | |
| 1261 | "item-properties-set-midi-items-to-use-current-tempo-and-ignore-project-tempo-changes-set-item-timebase-to-time": 43094, | |
| 1262 | "item-properties-set-midi-items-to-follow-project-tempo-changes-set-item-timebase-to-beats-position-length-rate": | |
| 1263 | 43095, | |
| 1264 | "item-properties-set-midi-items-to-use-current-tempo-and-ignore-project-tempo-changes-set-item-timebase-to-beats-position-only": | |
| 1265 | 43096, | |
| 1266 | "item-properties-set-midi-items-to-use-current-tempo-and-ignore-project-tempo-changes-set-item-timebase-to-time": | |
| 1267 | 43094, | |
| 1262 | 1268 | "item-properties-set-take-channel-mode-to-mono-channel-03": 41388, |
| 1263 | 1269 | "item-properties-set-take-channel-mode-to-mono-channel-04": 41389, |
| 1264 | 1270 | "item-properties-set-take-channel-mode-to-mono-channel-05": 41390, |
| ... | ... | @@ -1812,12 +1818,14 @@ export const REAPER_ACTIONS = { |
| 1812 | 1818 | "options-add-edge-points-when-moving-envelope-points-with-items": 40648, |
| 1813 | 1819 | "options-add-edge-points-when-moving-multiple-envelope-points": 42030, |
| 1814 | 1820 | "options-add-envelope-edge-points-when-ripple-editing-or-inserting-time": 40649, |
| 1815 | "options-allow-drag-drop-media-import-to-target-the-top-part-of-a-track-to-insert-a-new-track-to-receive-the-media": 42477, | |
| 1821 | "options-allow-drag-drop-media-import-to-target-the-top-part-of-a-track-to-insert-a-new-track-to-receive-the-media": | |
| 1822 | 42477, | |
| 1816 | 1823 | "options-allow-selecting-empty-takes": 41355, |
| 1817 | 1824 | "options-always-record-to-automation-items": 42212, |
| 1818 | 1825 | "options-always-trim-content-behind-razor-edits-otherwise-follow-media-item-editing-preferences": 42421, |
| 1819 | 1826 | "options-auto-crossfade-media-items-when-editing": 40041, |
| 1820 | "options-automatically-insert-automation-item-when-activating-envelope-that-is-bypassed-outside-of-automation-items-and-not-displayed-in-envelope-lane": 42220, | |
| 1827 | "options-automatically-insert-automation-item-when-activating-envelope-that-is-bypassed-outside-of-automation-items-and-not-displayed-in-envelope-lane": | |
| 1828 | 42220, | |
| 1821 | 1829 | "options-automation-item-baseline-amplitude-edits-affect-pooled-copies": 42194, |
| 1822 | 1830 | "options-automation-items-connect-to-the-underlying-envelope-on-both-sides": 42205, |
| 1823 | 1831 | "options-automation-items-connect-to-the-underlying-envelope-on-the-right-side": 42204, |
| ... | ... | @@ -2307,8 +2315,10 @@ export const REAPER_ACTIONS = { |
| 2307 | 2315 | "sws-aw-play-stop-automatically-group-simultaneously-recorded-items-deprecated": 53503, |
| 2308 | 2316 | "sws-aw-record-automatically-group-simultaneously-recorded-items-deprecated": 53500, |
| 2309 | 2317 | "sws-aw-record-conditional-normal-or-time-selection-only": 53497, |
| 2310 | "sws-aw-record-conditional-normal-or-time-selection-only-automatically-group-simultaneously-recorded-items-deprecated": 53501, | |
| 2311 | "sws-aw-record-conditional-normal-time-selection-item-selection-automatically-group-simultaneously-recorded-items-deprecated": 53502, | |
| 2318 | "sws-aw-record-conditional-normal-or-time-selection-only-automatically-group-simultaneously-recorded-items-deprecated": | |
| 2319 | 53501, | |
| 2320 | "sws-aw-record-conditional-normal-time-selection-item-selection-automatically-group-simultaneously-recorded-items-deprecated": | |
| 2321 | 53502, | |
| 2312 | 2322 | "sws-aw-record-conditional-normal-time-selection-or-item-selection": 53498, |
| 2313 | 2323 | "sws-aw-remove-overlaps-in-selected-items-preserving-item-starts": 53496, |
| 2314 | 2324 | "sws-aw-remove-tracks-items-env-obeying-time-selection-and-leaving-children": 53554, |
| ... | ... | @@ -2383,24 +2393,34 @@ export const REAPER_ACTIONS = { |
| 2383 | 2393 | "sws-br-apply-next-action-to-all-visible-envelopes-in-selected-tracks": 54100, |
| 2384 | 2394 | "sws-br-apply-next-action-to-all-visible-envelopes-in-selected-tracks-if-there-is-no-track-envelope-selected": 54102, |
| 2385 | 2395 | "sws-br-apply-next-action-to-all-visible-record-armed-envelopes-in-selected-tracks": 54101, |
| 2386 | "sws-br-apply-next-action-to-all-visible-record-armed-envelopes-in-selected-tracks-if-there-is-no-track-envelope-selected": 54103, | |
| 2396 | "sws-br-apply-next-action-to-all-visible-record-armed-envelopes-in-selected-tracks-if-there-is-no-track-envelope-selected": | |
| 2397 | 54103, | |
| 2387 | 2398 | "sws-br-check-for-new-sws-version": 55821, |
| 2388 | 2399 | "sws-br-contextual-toolbars": 53938, |
| 2389 | 2400 | "sws-br-convert-project-markers-to-tempo-markers": 54846, |
| 2390 | "sws-br-convert-selected-envelope-s-curve-in-time-selection-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor": 54051, | |
| 2391 | "sws-br-convert-selected-envelope-s-curve-in-time-selection-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor-clear-existing-events": 54052, | |
| 2392 | "sws-br-convert-selected-points-in-selected-envelope-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor": 54049, | |
| 2393 | "sws-br-convert-selected-points-in-selected-envelope-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor-clear-existing-events": 54050, | |
| 2401 | "sws-br-convert-selected-envelope-s-curve-in-time-selection-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor": | |
| 2402 | 54051, | |
| 2403 | "sws-br-convert-selected-envelope-s-curve-in-time-selection-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor-clear-existing-events": | |
| 2404 | 54052, | |
| 2405 | "sws-br-convert-selected-points-in-selected-envelope-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor": | |
| 2406 | 54049, | |
| 2407 | "sws-br-convert-selected-points-in-selected-envelope-to-cc-events-in-last-clicked-cc-lane-in-last-active-midi-editor-clear-existing-events": | |
| 2408 | 54050, | |
| 2394 | 2409 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks": 54072, |
| 2395 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks-paste-at-edit-cursor": 54076, | |
| 2396 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-record-armed-in-envelopes-of-selected-tracks": 54073, | |
| 2397 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-record-armed-in-envelopes-of-selected-tracks-paste-at-edit-cursor": 54077, | |
| 2410 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks-paste-at-edit-cursor": | |
| 2411 | 54076, | |
| 2412 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-record-armed-in-envelopes-of-selected-tracks": | |
| 2413 | 54073, | |
| 2414 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-all-visible-record-armed-in-envelopes-of-selected-tracks-paste-at-edit-cursor": | |
| 2415 | 54077, | |
| 2398 | 2416 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-envelope-at-mouse-cursor": 54079, |
| 2399 | 2417 | "sws-br-copy-points-in-time-selection-in-selected-envelope-to-envelope-at-mouse-cursor-paste-at-edit-cursor": 54081, |
| 2400 | 2418 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks": 54070, |
| 2401 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks-paste-at-edit-cursor": 54074, | |
| 2419 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-envelopes-in-selected-tracks-paste-at-edit-cursor": | |
| 2420 | 54074, | |
| 2402 | 2421 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-record-armed-envelopes-in-selected-tracks": 54071, |
| 2403 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-record-armed-envelopes-in-selected-tracks-paste-at-edit-cursor": 54075, | |
| 2422 | "sws-br-copy-selected-points-in-selected-envelope-to-all-visible-record-armed-envelopes-in-selected-tracks-paste-at-edit-cursor": | |
| 2423 | 54075, | |
| 2404 | 2424 | "sws-br-copy-selected-points-in-selected-envelope-to-envelope-at-mouse-cursor": 54078, |
| 2405 | 2425 | "sws-br-copy-selected-points-in-selected-envelope-to-to-envelope-at-mouse-cursor-paste-at-edit-cursor": 54080, |
| 2406 | 2426 | "sws-br-copy-take-media-source-file-path-of-selected-items-to-clipboard": 54503, |
| ... | ... | @@ -2437,7 +2457,8 @@ export const REAPER_ACTIONS = { |
| 2437 | 2457 | "sws-br-delete-tempo-marker-preserve-overall-tempo-and-positions-if-possible": 54838, |
| 2438 | 2458 | "sws-br-disable-ignore-project-tempo-for-selected-midi-items": 54465, |
| 2439 | 2459 | "sws-br-disable-ignore-project-tempo-for-selected-midi-items-preserving-time-position-of-midi-events": 54466, |
| 2440 | "sws-br-enable-ignore-project-tempo-for-selected-midi-items-preserving-time-position-of-midi-events-use-tempo-at-item-s-start": 54468, | |
| 2460 | "sws-br-enable-ignore-project-tempo-for-selected-midi-items-preserving-time-position-of-midi-events-use-tempo-at-item-s-start": | |
| 2461 | 54468, | |
| 2441 | 2462 | "sws-br-enable-ignore-project-tempo-for-selected-midi-items-use-tempo-at-item-s-start": 54467, |
| 2442 | 2463 | "sws-br-exclusive-toggle-contextual-toolbar-under-mouse-cursor-preset-1": 53979, |
| 2443 | 2464 | "sws-br-exclusive-toggle-contextual-toolbar-under-mouse-cursor-preset-2": 53984, |
| ... | ... | @@ -2594,12 +2615,16 @@ export const REAPER_ACTIONS = { |
| 2594 | 2615 | "sws-br-options-toggle-scroll-view-to-edit-cursor-on-stop": 54713, |
| 2595 | 2616 | "sws-br-options-toggle-send-all-notes-off-on-stop-play": 54691, |
| 2596 | 2617 | "sws-br-options-toggle-stop-repeat-playback-at-end-of-project": 54712, |
| 2597 | "sws-br-play-from-edit-cursor-position-and-solo-item-and-track-under-mouse-for-the-duration-perform-until-shortcut-released": 54863, | |
| 2598 | "sws-br-play-from-edit-cursor-position-and-solo-track-under-mouse-for-the-duration-perform-until-shortcut-released": 54862, | |
| 2618 | "sws-br-play-from-edit-cursor-position-and-solo-item-and-track-under-mouse-for-the-duration-perform-until-shortcut-released": | |
| 2619 | 54863, | |
| 2620 | "sws-br-play-from-edit-cursor-position-and-solo-track-under-mouse-for-the-duration-perform-until-shortcut-released": | |
| 2621 | 54862, | |
| 2599 | 2622 | "sws-br-play-from-edit-cursor-position-perform-until-shortcut-released": 54861, |
| 2600 | 2623 | "sws-br-play-from-mouse-cursor-position": 54459, |
| 2601 | "sws-br-play-from-mouse-cursor-position-and-solo-item-and-track-under-mouse-for-the-duration-perform-until-shortcut-released": 54860, | |
| 2602 | "sws-br-play-from-mouse-cursor-position-and-solo-track-under-mouse-for-the-duration-perform-until-shortcut-released": 54859, | |
| 2624 | "sws-br-play-from-mouse-cursor-position-and-solo-item-and-track-under-mouse-for-the-duration-perform-until-shortcut-released": | |
| 2625 | 54860, | |
| 2626 | "sws-br-play-from-mouse-cursor-position-and-solo-track-under-mouse-for-the-duration-perform-until-shortcut-released": | |
| 2627 | 54859, | |
| 2603 | 2628 | "sws-br-play-from-mouse-cursor-position-perform-until-shortcut-released": 54858, |
| 2604 | 2629 | "sws-br-play-pause-from-mouse-cursor-position": 54460, |
| 2605 | 2630 | "sws-br-play-stop-from-mouse-cursor-position": 54461, |
| ... | ... | @@ -2608,14 +2633,16 @@ export const REAPER_ACTIONS = { |
| 2608 | 2633 | "sws-br-preview-media-item-under-mouse-and-pause-during-preview-start-from-mouse-cursor-position": 54726, |
| 2609 | 2634 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume": 54727, |
| 2610 | 2635 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview": 54730, |
| 2611 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": 54731, | |
| 2636 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2637 | 54731, | |
| 2612 | 2638 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume-start-from-mouse-position": 54728, |
| 2613 | 2639 | "sws-br-preview-media-item-under-mouse-at-track-fader-volume-sync-with-next-measure": 54729, |
| 2614 | 2640 | "sws-br-preview-media-item-under-mouse-start-from-mouse-cursor-position": 54723, |
| 2615 | 2641 | "sws-br-preview-media-item-under-mouse-sync-with-next-measure": 54724, |
| 2616 | 2642 | "sws-br-preview-media-item-under-mouse-through-track": 54732, |
| 2617 | 2643 | "sws-br-preview-media-item-under-mouse-through-track-and-pause-during-preview": 54735, |
| 2618 | "sws-br-preview-media-item-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": 54736, | |
| 2644 | "sws-br-preview-media-item-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2645 | 54736, | |
| 2619 | 2646 | "sws-br-preview-media-item-under-mouse-through-track-start-from-mouse-position": 54733, |
| 2620 | 2647 | "sws-br-preview-media-item-under-mouse-through-track-sync-with-next-measure": 54734, |
| 2621 | 2648 | "sws-br-preview-take-under-mouse": 54752, |
| ... | ... | @@ -2623,7 +2650,8 @@ export const REAPER_ACTIONS = { |
| 2623 | 2650 | "sws-br-preview-take-under-mouse-and-pause-during-preview-start-from-mouse-cursor-position": 54756, |
| 2624 | 2651 | "sws-br-preview-take-under-mouse-at-track-fader-volume": 54757, |
| 2625 | 2652 | "sws-br-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview": 54760, |
| 2626 | "sws-br-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": 54761, | |
| 2653 | "sws-br-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2654 | 54761, | |
| 2627 | 2655 | "sws-br-preview-take-under-mouse-at-track-fader-volume-start-from-mouse-position": 54758, |
| 2628 | 2656 | "sws-br-preview-take-under-mouse-at-track-fader-volume-sync-with-next-measure": 54759, |
| 2629 | 2657 | "sws-br-preview-take-under-mouse-start-from-mouse-cursor-position": 54753, |
| ... | ... | @@ -2851,9 +2879,12 @@ export const REAPER_ACTIONS = { |
| 2851 | 2879 | "sws-br-select-dips-in-envelope": 54058, |
| 2852 | 2880 | "sws-br-select-dips-in-envelope-add-to-selection": 54057, |
| 2853 | 2881 | "sws-br-select-envelope-at-mouse-cursor": 54094, |
| 2854 | "sws-br-select-envelope-at-mouse-cursor-and-freehand-draw-envelope-while-snapping-points-to-left-side-grid-line-perform-until-shortcut-released": 54857, | |
| 2855 | "sws-br-select-envelope-at-mouse-cursor-and-set-closest-envelope-point-s-value-to-mouse-cursor-perform-until-shortcut-released": 54855, | |
| 2856 | "sws-br-select-envelope-at-mouse-cursor-and-set-closest-left-side-envelope-point-s-value-to-mouse-cursor-perform-until-shortcut-released": 54856, | |
| 2882 | "sws-br-select-envelope-at-mouse-cursor-and-freehand-draw-envelope-while-snapping-points-to-left-side-grid-line-perform-until-shortcut-released": | |
| 2883 | 54857, | |
| 2884 | "sws-br-select-envelope-at-mouse-cursor-and-set-closest-envelope-point-s-value-to-mouse-cursor-perform-until-shortcut-released": | |
| 2885 | 54855, | |
| 2886 | "sws-br-select-envelope-at-mouse-cursor-and-set-closest-left-side-envelope-point-s-value-to-mouse-cursor-perform-until-shortcut-released": | |
| 2887 | 54856, | |
| 2857 | 2888 | "sws-br-select-envelope-point-at-mouse-cursor": 54096, |
| 2858 | 2889 | "sws-br-select-envelope-point-at-mouse-cursor-selected-envelope-only": 54095, |
| 2859 | 2890 | "sws-br-select-envelope-points-between-grid": 54037, |
| ... | ... | @@ -2909,14 +2940,16 @@ export const REAPER_ACTIONS = { |
| 2909 | 2940 | "sws-br-toggle-preview-media-item-under-mouse-and-pause-during-preview-start-from-mouse-cursor-position": 54741, |
| 2910 | 2941 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume": 54742, |
| 2911 | 2942 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview": 54745, |
| 2912 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": 54746, | |
| 2943 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2944 | 54746, | |
| 2913 | 2945 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume-start-from-mouse-position": 54743, |
| 2914 | 2946 | "sws-br-toggle-preview-media-item-under-mouse-at-track-fader-volume-sync-with-next-measure": 54744, |
| 2915 | 2947 | "sws-br-toggle-preview-media-item-under-mouse-start-from-mouse-position": 54738, |
| 2916 | 2948 | "sws-br-toggle-preview-media-item-under-mouse-sync-with-next-measure": 54739, |
| 2917 | 2949 | "sws-br-toggle-preview-media-item-under-mouse-through-track": 54747, |
| 2918 | 2950 | "sws-br-toggle-preview-media-item-under-mouse-through-track-and-pause-during-preview": 54750, |
| 2919 | "sws-br-toggle-preview-media-item-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": 54751, | |
| 2951 | "sws-br-toggle-preview-media-item-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2952 | 54751, | |
| 2920 | 2953 | "sws-br-toggle-preview-media-item-under-mouse-through-track-start-from-mouse-position": 54748, |
| 2921 | 2954 | "sws-br-toggle-preview-media-item-under-mouse-through-track-sync-with-next-measure": 54749, |
| 2922 | 2955 | "sws-br-toggle-preview-take-under-mouse": 54767, |
| ... | ... | @@ -2924,14 +2957,16 @@ export const REAPER_ACTIONS = { |
| 2924 | 2957 | "sws-br-toggle-preview-take-under-mouse-and-pause-during-preview-start-from-mouse-cursor-position": 54771, |
| 2925 | 2958 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume": 54772, |
| 2926 | 2959 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview": 54775, |
| 2927 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": 54776, | |
| 2960 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2961 | 54776, | |
| 2928 | 2962 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume-start-from-mouse-position": 54773, |
| 2929 | 2963 | "sws-br-toggle-preview-take-under-mouse-at-track-fader-volume-sync-with-next-measure": 54774, |
| 2930 | 2964 | "sws-br-toggle-preview-take-under-mouse-start-from-mouse-position": 54768, |
| 2931 | 2965 | "sws-br-toggle-preview-take-under-mouse-sync-with-next-measure": 54769, |
| 2932 | 2966 | "sws-br-toggle-preview-take-under-mouse-through-track": 54777, |
| 2933 | 2967 | "sws-br-toggle-preview-take-under-mouse-through-track-and-pause-during-preview": 54780, |
| 2934 | "sws-br-toggle-preview-take-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": 54781, | |
| 2968 | "sws-br-toggle-preview-take-under-mouse-through-track-and-pause-during-preview-start-from-mouse-cursor-position": | |
| 2969 | 54781, | |
| 2935 | 2970 | "sws-br-toggle-preview-take-under-mouse-through-track-start-from-mouse-position": 54778, |
| 2936 | 2971 | "sws-br-toggle-preview-take-under-mouse-through-track-sync-with-next-measure": 54779, |
| 2937 | 2972 | "sws-br-toggle-show-active-mute-send-envelopes-for-selected-tracks": 54153, |
| ... | ... | @@ -4405,13 +4440,16 @@ export const REAPER_ACTIONS = { |
| 4405 | 4440 | "sws-wait-for-next-beat-if-playing": 53664, |
| 4406 | 4441 | "sws-wait-until-end-of-loop-if-playing": 53665, |
| 4407 | 4442 | "sws-wol-adjust-envelope-or-track-height-under-mouse-cursor-midi-cc-relative-mousewheel": 54892, |
| 4408 | "sws-wol-adjust-envelope-or-track-height-under-mouse-cursor-zoom-center-to-mouse-cursor-midi-cc-relative-mousewheel": 54893, | |
| 4443 | "sws-wol-adjust-envelope-or-track-height-under-mouse-cursor-zoom-center-to-mouse-cursor-midi-cc-relative-mousewheel": | |
| 4444 | 54893, | |
| 4409 | 4445 | "sws-wol-adjust-selected-envelope-height-midi-cc-relative-mousewheel": 54886, |
| 4410 | 4446 | "sws-wol-adjust-selected-envelope-height-zoom-center-to-middle-arrange-midi-cc-relative-mousewheel": 54887, |
| 4411 | 4447 | "sws-wol-adjust-selected-envelope-height-zoom-center-to-mouse-cursor-midi-cc-relative-mousewheel": 54888, |
| 4412 | 4448 | "sws-wol-adjust-selected-envelope-or-last-touched-track-height-midi-cc-relative-mousewheel": 54889, |
| 4413 | "sws-wol-adjust-selected-envelope-or-last-touched-track-height-zoom-center-to-middle-arrange-midi-cc-relative-mousewheel": 54890, | |
| 4414 | "sws-wol-adjust-selected-envelope-or-last-touched-track-height-zoom-center-to-mouse-cursor-midi-cc-relative-mousewheel": 54891, | |
| 4449 | "sws-wol-adjust-selected-envelope-or-last-touched-track-height-zoom-center-to-middle-arrange-midi-cc-relative-mousewheel": | |
| 4450 | 54890, | |
| 4451 | "sws-wol-adjust-selected-envelope-or-last-touched-track-height-zoom-center-to-mouse-cursor-midi-cc-relative-mousewheel": | |
| 4452 | 54891, | |
| 4415 | 4453 | "sws-wol-apply-height-to-selected-envelope-slot-1": 54912, |
| 4416 | 4454 | "sws-wol-apply-height-to-selected-envelope-slot-2": 54913, |
| 4417 | 4455 | "sws-wol-apply-height-to-selected-envelope-slot-3": 54914, |
| ... | ... | @@ -4794,8 +4832,10 @@ export const REAPER_ACTIONS = { |
| 4794 | 4832 | "toolbars-switch-to-toolbar-9": 41948, |
| 4795 | 4833 | "track-2nd-pass-render-selected-area-of-tracks-to-mono-post-fader-stem-tracks-and-mute-originals": 42415, |
| 4796 | 4834 | "track-2nd-pass-render-selected-area-of-tracks-to-mono-stem-tracks-and-mute-originals": 42418, |
| 4797 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-parent-send-only-post-fader-stem-tracks-and-mute-originals": 42593, | |
| 4798 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-parent-send-only-stem-tracks-and-mute-originals": 42594, | |
| 4835 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-parent-send-only-post-fader-stem-tracks-and-mute-originals": | |
| 4836 | 42593, | |
| 4837 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-parent-send-only-stem-tracks-and-mute-originals": | |
| 4838 | 42594, | |
| 4799 | 4839 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-post-fader-stem-tracks-and-mute-originals": 42414, |
| 4800 | 4840 | "track-2nd-pass-render-selected-area-of-tracks-to-multichannel-stem-tracks-and-mute-originals": 42417, |
| 4801 | 4841 | "track-2nd-pass-render-selected-area-of-tracks-to-stereo-post-fader-stem-tracks-and-mute-originals": 42413, |
| ... | ... | @@ -5012,7 +5052,8 @@ export const REAPER_ACTIONS = { |
| 5012 | 5052 | "track-rename-last-touched-track": 40696, |
| 5013 | 5053 | "track-render-selected-area-of-tracks-to-mono-post-fader-stem-tracks-and-mute-originals": 41718, |
| 5014 | 5054 | "track-render-selected-area-of-tracks-to-mono-stem-tracks-and-mute-originals": 41721, |
| 5015 | "track-render-selected-area-of-tracks-to-multichannel-parent-send-only-post-fader-stem-tracks-and-mute-originals": 42591, | |
| 5055 | "track-render-selected-area-of-tracks-to-multichannel-parent-send-only-post-fader-stem-tracks-and-mute-originals": | |
| 5056 | 42591, | |
| 5016 | 5057 | "track-render-selected-area-of-tracks-to-multichannel-parent-send-only-stem-tracks-and-mute-originals": 42592, |
| 5017 | 5058 | "track-render-selected-area-of-tracks-to-multichannel-post-fader-stem-tracks-and-mute-originals": 41717, |
| 5018 | 5059 | "track-render-selected-area-of-tracks-to-multichannel-stem-tracks-and-mute-originals": 41720, |
src/Reaper/generate-actions.ts+6-15| ... | ... | @@ -1,12 +1,5 @@ |
| 1 | 1 | import { execFile } from "node:child_process"; |
| 2 | import { | |
| 3 | access, | |
| 4 | mkdir, | |
| 5 | mkdtemp, | |
| 6 | readFile, | |
| 7 | rm, | |
| 8 | writeFile, | |
| 9 | } from "node:fs/promises"; | |
| 2 | import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; | |
| 10 | 3 | import { tmpdir } from "node:os"; |
| 11 | 4 | import { dirname, join, resolve } from "node:path"; |
| 12 | 5 | import process from "node:process"; |
| ... | ... | @@ -76,10 +69,10 @@ function parseRawActions(value: unknown): RawReaperAction[] { |
| 76 | 69 | |
| 77 | 70 | return value.flatMap((entry) => { |
| 78 | 71 | if ( |
| 79 | !entry || | |
| 80 | typeof entry !== "object" || | |
| 81 | !("commandId" in entry) || | |
| 82 | !("name" in entry) | |
| 72 | !entry | |
| 73 | || typeof entry !== "object" | |
| 74 | || !("commandId" in entry) | |
| 75 | || !("name" in entry) | |
| 83 | 76 | ) { |
| 84 | 77 | return []; |
| 85 | 78 | } |
| ... | ... | @@ -147,9 +140,7 @@ function renderActionsFile(actions: ReadonlyArray<GeneratedReaperAction>) { |
| 147 | 140 | "// Source: REAPER main action section via kbd_enumerateActions()/kbd_getTextFromCmd().", |
| 148 | 141 | "", |
| 149 | 142 | "export const REAPER_ACTIONS = {", |
| 150 | ...actions.map((action) => | |
| 151 | ` ${JSON.stringify(action.actionId)}: ${action.commandId},` | |
| 152 | ), | |
| 143 | ...actions.map((action) => ` ${JSON.stringify(action.actionId)}: ${action.commandId},`), | |
| 153 | 144 | "} as const satisfies Record<string, number>;", |
| 154 | 145 | "", |
| 155 | 146 | "export type ReaperActionId = keyof typeof REAPER_ACTIONS;", |
src/SpeedEditor.ts+22-22| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | import { Events } from "@clo/lib/Events.ts"; |
| 2 | import * as log from "@clo/lib/log.ts"; | |
| 2 | 3 | import { defer } from "@clo/lib/ts.ts"; |
| 3 | 4 | import type { Dispose, Timer } from "@clo/lib/ts.ts"; |
| 4 | 5 | import type { Mac } from "./Mac"; |
| 5 | import * as log from "@clo/lib/log.ts"; | |
| 6 | 6 | |
| 7 | 7 | const SPEED_EDITOR_VENDOR_ID = 0x1edb; |
| 8 | 8 | const SPEED_EDITOR_PRODUCT_ID = 0xda0e; |
| ... | ... | @@ -215,8 +215,8 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 215 | 215 | } |
| 216 | 216 | |
| 217 | 217 | onDoublePress(key: SpeedEditor.Key, listener: () => void): Dispose { |
| 218 | const listeners = this.#doublePressListeners.get(key) ?? | |
| 219 | new Set<() => void>(); | |
| 218 | const listeners = this.#doublePressListeners.get(key) | |
| 219 | ?? new Set<() => void>(); | |
| 220 | 220 | listeners.add(listener); |
| 221 | 221 | this.#doublePressListeners.set(key, listeners); |
| 222 | 222 | |
| ... | ... | @@ -236,7 +236,7 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 236 | 236 | this.#ready = false; |
| 237 | 237 | this.#refreshRequested = false; |
| 238 | 238 | this.#stopHotplugMonitoring?.(); |
| 239 | this.#stopHotplugMonitoring = null | |
| 239 | this.#stopHotplugMonitoring = null; | |
| 240 | 240 | this.#disconnect(false); |
| 241 | 241 | this.emit("close"); |
| 242 | 242 | } |
| ... | ... | @@ -267,8 +267,8 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 267 | 267 | |
| 268 | 268 | #matchesHotplugDevice(device: import("usb").Device) { |
| 269 | 269 | const descriptor = device.deviceDescriptor; |
| 270 | return descriptor.idVendor === this.#options.vendorId && | |
| 271 | descriptor.idProduct === this.#options.productId; | |
| 270 | return descriptor.idVendor === this.#options.vendorId | |
| 271 | && descriptor.idProduct === this.#options.productId; | |
| 272 | 272 | } |
| 273 | 273 | |
| 274 | 274 | async #refreshConnection() { |
| ... | ... | @@ -309,8 +309,8 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | 311 | const currentKey = getDeviceKey(this.#deviceInfo); |
| 312 | const currentStillPresent = currentKey !== null && | |
| 313 | devices.some((device) => getDeviceKey(device) === currentKey); | |
| 312 | const currentStillPresent = currentKey !== null | |
| 313 | && devices.some((device) => getDeviceKey(device) === currentKey); | |
| 314 | 314 | |
| 315 | 315 | if (this.#device && !currentStillPresent) { |
| 316 | 316 | this.#disconnect(true); |
| ... | ... | @@ -330,8 +330,8 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 330 | 330 | |
| 331 | 331 | #selectDevice(devices: ReadonlyArray<SpeedEditor.DeviceInfo>) { |
| 332 | 332 | if (this.#options.path) { |
| 333 | return devices.find((device) => device.path === this.#options.path) ?? | |
| 334 | null; | |
| 333 | return devices.find((device) => device.path === this.#options.path) | |
| 334 | ?? null; | |
| 335 | 335 | } |
| 336 | 336 | |
| 337 | 337 | return devices[0] ?? null; |
| ... | ... | @@ -611,16 +611,16 @@ export class SpeedEditor extends Events<SpeedEditor.EventMap> { |
| 611 | 611 | } |
| 612 | 612 | |
| 613 | 613 | static camNumbersToNumpad(speededitor: Pick<SpeedEditor, "onPress">, mac: Pick<Mac, "pressKey">) { |
| 614 | speededitor.onPress("cam1", () => mac.pressKey('numpad1')); | |
| 615 | speededitor.onPress("cam2", () => mac.pressKey('numpad2')); | |
| 616 | speededitor.onPress("cam3", () => mac.pressKey('numpad3')); | |
| 617 | speededitor.onPress("cam4", () => mac.pressKey('numpad4')); | |
| 618 | speededitor.onPress("cam5", () => mac.pressKey('numpad5')); | |
| 619 | speededitor.onPress("cam6", () => mac.pressKey('numpad6')); | |
| 620 | speededitor.onPress("cam7", () => mac.pressKey('numpad7')); | |
| 621 | speededitor.onPress("cam8", () => mac.pressKey('numpad8')); | |
| 622 | speededitor.onPress("cam9", () => mac.pressKey('numpad9')); | |
| 623 | speededitor.onPress("liveOverwrite", () => mac.pressKey('numpad0')); | |
| 614 | speededitor.onPress("cam1", () => mac.pressKey("numpad1")); | |
| 615 | speededitor.onPress("cam2", () => mac.pressKey("numpad2")); | |
| 616 | speededitor.onPress("cam3", () => mac.pressKey("numpad3")); | |
| 617 | speededitor.onPress("cam4", () => mac.pressKey("numpad4")); | |
| 618 | speededitor.onPress("cam5", () => mac.pressKey("numpad5")); | |
| 619 | speededitor.onPress("cam6", () => mac.pressKey("numpad6")); | |
| 620 | speededitor.onPress("cam7", () => mac.pressKey("numpad7")); | |
| 621 | speededitor.onPress("cam8", () => mac.pressKey("numpad8")); | |
| 622 | speededitor.onPress("cam9", () => mac.pressKey("numpad9")); | |
| 623 | speededitor.onPress("liveOverwrite", () => mac.pressKey("numpad0")); | |
| 624 | 624 | } |
| 625 | 625 | } |
| 626 | 626 | |
| ... | ... | @@ -909,8 +909,8 @@ function getDeviceKey(device: SpeedEditor.DeviceInfo | null) { |
| 909 | 909 | return null; |
| 910 | 910 | } |
| 911 | 911 | |
| 912 | return device.path ?? | |
| 913 | [ | |
| 912 | return device.path | |
| 913 | ?? [ | |
| 914 | 914 | device.vendorId, |
| 915 | 915 | device.productId, |
| 916 | 916 | device.serialNumber ?? "", |
src/config.ts+11-11| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | import { Events } from "@clo/lib/Events.ts"; | |
| 2 | import * as console from "@clo/lib/log.ts"; | |
| 1 | 3 | import * as ts from "@clo/lib/ts.ts"; |
| 2 | 4 | import type { Dispose } from "@clo/lib/ts.ts"; |
| 3 | 5 | import * as fs from "node:fs/promises"; |
| ... | ... | @@ -5,8 +7,6 @@ import * as path from "node:path"; |
| 5 | 7 | import * as url from "node:url"; |
| 6 | 8 | import { Mac } from "./Mac.ts"; |
| 7 | 9 | import { SpeedEditor } from "./SpeedEditor.ts"; |
| 8 | import { Events } from "@clo/lib/Events.ts"; | |
| 9 | import * as console from "@clo/lib/log.ts"; | |
| 10 | 10 | |
| 11 | 11 | export interface Configure { |
| 12 | 12 | /** Events are only active when the application is active. */ |
| ... | ... | @@ -34,9 +34,9 @@ interface AppDefinition { |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | export type AppEvents = { |
| 37 | "focus": [], | |
| 38 | "blur": [], | |
| 39 | } | |
| 37 | "focus": []; | |
| 38 | "blur": []; | |
| 39 | }; | |
| 40 | 40 | |
| 41 | 41 | export function forApp( |
| 42 | 42 | bundle: Mac.BundleId, |
| ... | ... | @@ -151,8 +151,8 @@ export class AppSpeedEditor extends Events<SpeedEditor.EventMap> { |
| 151 | 151 | onDoublePress(key: SpeedEditor.Key, listener: () => void): Dispose { |
| 152 | 152 | const pair = { key, listener }; |
| 153 | 153 | this.#doubleKeyEvents.add(pair); |
| 154 | this.#enabled && | |
| 155 | this.#enabledStack.use(this.#source.onDoublePress(key, listener)); | |
| 154 | this.#enabled | |
| 155 | && this.#enabledStack.use(this.#source.onDoublePress(key, listener)); | |
| 156 | 156 | return ts.defer(() => { |
| 157 | 157 | throw new Error("TODO"); |
| 158 | 158 | }); |
| ... | ... | @@ -199,12 +199,12 @@ export async function runConfigs(dir: string) { |
| 199 | 199 | if (!speededitor.connected) { |
| 200 | 200 | console.warn("Speed Editor is not connected"); |
| 201 | 201 | } |
| 202 | speededitor.on('connect', () => { | |
| 202 | speededitor.on("connect", () => { | |
| 203 | 203 | console.info("Speed Editor connected"); |
| 204 | }) | |
| 205 | speededitor.on('disconnect', () => { | |
| 204 | }); | |
| 205 | speededitor.on("disconnect", () => { | |
| 206 | 206 | console.warn("Speed Editor lost connection"); |
| 207 | }) | |
| 207 | }); | |
| 208 | 208 | |
| 209 | 209 | const instances = new Map<Mac.BundleId, AppInstance>(); |
| 210 | 210 | const pendingInstances = new Map<Mac.BundleId, Promise<AppInstance | null>>(); |