diff --git a/.yarn/cache/@types-core-js-npm-2.5.8-4719cbbab8-58c4b86102.zip b/.yarn/cache/@types-core-js-npm-2.5.8-4719cbbab8-58c4b86102.zip new file mode 100644 index 0000000..40a404e Binary files /dev/null and b/.yarn/cache/@types-core-js-npm-2.5.8-4719cbbab8-58c4b86102.zip differ diff --git a/.yarn/cache/core-js-npm-3.39.0-4c420e59a7-a3d34e6697.zip b/.yarn/cache/core-js-npm-3.39.0-4c420e59a7-a3d34e6697.zip new file mode 100644 index 0000000..89df862 Binary files /dev/null and b/.yarn/cache/core-js-npm-3.39.0-4c420e59a7-a3d34e6697.zip differ diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 32362a3..0ba1873 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/package.json b/package.json index d9f8008..4cd9f3b 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,11 @@ "description": "Library of useful Max for Live objects", "private": true, "dependencies": { + "core-js": "^3.39.0", "dotenv": "^8.2.0" }, "devDependencies": { + "@types/core-js": "^2.5.8", "prettier": "^3.3.3", "ts-loader": "^9.5.1", "typescript": "^5.5.3", diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..1a28cca --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1 @@ +export { default as launchpadColourIndices } from "./launchpadColourIndices"; diff --git a/src/config/launchpadColourIndices.ts b/src/config/launchpadColourIndices.ts new file mode 100644 index 0000000..7802329 --- /dev/null +++ b/src/config/launchpadColourIndices.ts @@ -0,0 +1,76 @@ +export default [ + 56, // salmon + 61, // frank orange + 100, // dirty gold + 73, // lemonade + 85, // lime + 87, // highlighter green + 88, // bianchi + 28, // turquoise + 91, // sky blue + 92, // sapphire + 40, // periwinkle + 82, // orchid + 58, // magenta + 3, // white + + 106, // fire hydrant red + 127, // tangerine + 117, // sand + 14, // sunshine yellow + 86, // terminal green + 19, // forest + 65, // tiffany blue + 68, // cyan + 39, // cerulean + 43, // united nations blue + 93, // amtethyst + 70, // iris + 53, // flamingo + 2, // aluminum + + 105, // terracotta + 107, // light salmon + 8, // whiskey + 73, // canary + 113, // primrose + 16, // wild willow + 24, // dark sea green + 114, // honeydew + 114, // pale turquoise + 118, // periwinkle + 2, // fog + 39, // dull lavender + 119, // whisper + 118, // silver chalice + + 2, // dusty pink + 105, // barley corn + 118, // pale oyster; difficult + 110, // dark khaki + 18, // pistachio + 102, // dollar bill + 89, // neptune + 89, // nepal + 36, // polo blue + 40, // vista blue + 2, // amethyst smoke + 118, // lilac + 70, // turkish rose + 117, // steel + + 121, // medium carmine + 83, // red ochre + 71, // coffee + 15, // durian yellow + 19, // pomelo green + 27, // apple + 65, // aquamarine + 68, // sea blue + 104, // cosmic cobalt + 112, // sapphire + 71, // plump purple + 70, // purpureus + 55, // fuchsia rose + 103, // eclipse +]; diff --git a/src/maxForLive.d.ts b/src/maxForLive.d.ts index 21b92e9..ae957f8 100644 --- a/src/maxForLive.d.ts +++ b/src/maxForLive.d.ts @@ -23,8 +23,9 @@ declare global { mode: number; type: string; info: string; - property: string; + property: string | null; call: Function; + freepeer: Function; get: Function; getcount: Function; getstring: Function; diff --git a/src/objects/betterLaunchpadColours/betterLaunchpadColours.ts b/src/objects/betterLaunchpadColours/betterLaunchpadColours.ts new file mode 100644 index 0000000..13f09f9 --- /dev/null +++ b/src/objects/betterLaunchpadColours/betterLaunchpadColours.ts @@ -0,0 +1,88 @@ +import "core-js"; +import type { Id } from "../../types"; +import { log, ApiManager, getCount } from "../../util"; +import { launchpadColourIndices } from "../../config"; + +autowatch = 1; +outlets = 3; + +enum LightType { + on, + blink, + pulse, + off, +} + +const apiMan = new ApiManager(); + +export function bang() { + const numberOfTracks = getCount("live_set tracks"); + for ( + let trackIndex = 0; + trackIndex < Math.min(8, numberOfTracks); + trackIndex++ + ) { + const numberOfClipSlots = getCount( + `live_set tracks ${trackIndex} clip_slots`, + ); + for ( + let clipSlotIndex = 0; + clipSlotIndex < Math.min(8, numberOfClipSlots); + clipSlotIndex++ + ) { + const clipSlotId = `live_set tracks ${trackIndex} clip_slots ${clipSlotIndex} has_clip`; + const clipId = `live_set tracks ${trackIndex} clip_slots ${clipSlotIndex} clip color_index`; + const padIndex = getPadIndex(trackIndex, clipSlotIndex); + const clipSlot = apiMan.make(clipSlotId, (hasClip) => { + log( + `Track ${trackIndex + 1} clip slot ${clipSlotIndex + 1} ${hasClip === 0 ? "is empty" : "has a clip"}`, + ); + if (hasClip === 0) { + clipSlot.killChildren(); + return; + } + const clip = clipSlot.add(clipId, (colourIndex) => { + log( + `Track ${trackIndex + 1} clip in slot ${clipSlotIndex + 1} has color index ${colourIndex} (pad index ${padIndex})`, + ); + sendPadLightMidiMessage( + LightType.on, + padIndex, + launchpadColourIndices[colourIndex], + ); + }); + if (clip) { + clip.start(); + } + }); + log("starting to observe slots and clips"); + clipSlot.start(); + } + } +} + +function getPadIndex(trackIndex: number, clipSlotIndex: number) { + return 80 - clipSlotIndex * 10 + trackIndex + 1; +} + +function sendPadLightMidiMessage( + lightType: LightType, + position: number, + colourIndex?: number, +) { + switch (lightType) { + case LightType.on: + outlet(0, [144, position, colourIndex]); + break; + case LightType.blink: + outlet(0, [144, position, 0]); + outlet(1, [145, position, colourIndex]); + break; + case LightType.pulse: + outlet(2, [146, position, colourIndex]); + break; + case LightType.off: + outlet(0, [144, position, 0]); + break; + } +} diff --git a/src/objects/betterLaunchpadColours/index.ts b/src/objects/betterLaunchpadColours/index.ts new file mode 100644 index 0000000..09b122c --- /dev/null +++ b/src/objects/betterLaunchpadColours/index.ts @@ -0,0 +1 @@ +export * from "./betterLaunchpadColours"; diff --git a/src/objects/betterLaunchpadColoursPlayground/betterLaunchpadColoursPlayground.ts b/src/objects/betterLaunchpadColoursPlayground/betterLaunchpadColoursPlayground.ts new file mode 100644 index 0000000..0f55274 --- /dev/null +++ b/src/objects/betterLaunchpadColoursPlayground/betterLaunchpadColoursPlayground.ts @@ -0,0 +1,482 @@ +import "../../polyfills/fill"; +import type { Id } from "../../types"; +import { log, ApiManager } from "../../util"; +import { launchpadColourIndices } from "../../config"; + +autowatch = 1; +outlets = 3; + +enum LightType { + on, + blink, + pulse, + off, +} + +export function print_rgb_values() { + const api = new LiveAPI("live_set"); + for (let rowIndex = 0; rowIndex < 5; rowIndex++) { + for (let colIndex = 0; colIndex < 14; colIndex++) { + api.goto(`live_set tracks ${colIndex} clip_slots ${rowIndex} clip`); + const colourIndex = api.get("color_index"); + const colourRgb = api.get("color"); + const row = rowIndex + 1; + const col = colIndex + 1; + log(`${colourIndex},${colourRgb},${row},${col}`); + } + } +} + +const apiMan = new ApiManager(); + +export function make_managed_api() { + apiMan.make( + "live_set tracks 0 clip_slots 0 clip color_index", + (message: string[]) => log(`Managed observation: ${message.join(" ")}`), + ); +} + +export function kill_managed_api() { + apiMan.kill("live_set tracks 0 clip_slots 0 clip color_index"); +} + +export function observe_selected_track() { + observeSelectedTrack( + (prevTrackIndex: number | null, trackIndex: number | null) => { + log(`Track index changed from ${prevTrackIndex} to ${trackIndex}`); + if (prevTrackIndex !== null) { + // actually, we don't have to bother with turning pad lights off, + // the control surface already does that + //sendPadLightMidiMessage(LightType.off, 11 + prevTrackIndex); + } + if (trackIndex !== null) { + sendPadLightMidiMessage(LightType.on, 11 + trackIndex, 80); + } + }, + ); +} + +export function print_track_colour(trackIndex: number) { + // everything is zero based, tracks 0 gets us track 1 + const track = new LiveAPI(`live_set tracks ${trackIndex}`); + // colour indices: + // 0: salmon (upper-left of the palette) + // 14: fire hydrant red (row 2, col 1) + // 28: terracotta (row 3, col 1) + // 69: eclipse (lower-right of the palette) + log(`Track #${trackIndex + 1} colour index:`, track.get("color_index")); +} + +export function observe_clips() { + function createObserver(padIndex: number) { + return (message: [string, number]) => { + const [propName, value] = message; + if (propName !== "color_index") { + return; + } + log(`Got colour index ${value} from a clip to set on pad ${padIndex}`); + sendPadLightMidiMessage( + LightType.on, + padIndex, + launchpadColourIndices[value], + ); + }; + } + + const api = new LiveAPI("live_set"); + const trackCount = api.getcount("tracks"); + for (let trackIndex = 0; trackIndex < Math.min(8, trackCount); trackIndex++) { + api.goto(`live_set tracks ${trackIndex}`); + const clipSlotCount = api.getcount("clip_slots"); + for ( + let clipSlotIndex = 0; + clipSlotIndex < Math.min(8, clipSlotCount); + clipSlotIndex++ + ) { + api.goto(`live_set tracks ${trackIndex} clip_slots ${clipSlotIndex}`); + const [hasClip] = api.get("has_clip"); + if (hasClip === 0) { + continue; + } + const clip = new LiveAPI( + createObserver(80 - clipSlotIndex * 10 + trackIndex + 1), + `live_set tracks ${trackIndex} clip_slots ${clipSlotIndex} clip`, + ); + clip.property = "color_index"; + } + } +} + +export function observe_clips_and_print_colour_index() { + function onClipChangePrintColourIndex(message: any[]) { + const [propName, value] = message; + if (propName !== "color_index") { + return; + } + log(`Got ${propName} from a clip: ${value}`); + } + + const api = new LiveAPI("live_set"); + const trackCount = api.getcount("tracks"); + for (let trackIndex = 0; trackIndex < Math.min(8, trackCount); trackIndex++) { + api.goto(`live_set tracks ${trackIndex}`); + const clipSlotCount = api.getcount("clip_slots"); + for ( + let clipSlotIndex = 0; + clipSlotIndex < Math.min(8, clipSlotCount); + clipSlotIndex++ + ) { + api.goto(`live_set tracks ${trackIndex} clip_slots ${clipSlotIndex}`); + const [hasClip] = api.get("has_clip"); + if (hasClip === 0) { + continue; + } + const clip = new LiveAPI( + onClipChangePrintColourIndex, + `live_set tracks ${trackIndex} clip_slots ${clipSlotIndex} clip`, + ); + clip.property = "color_index"; + } + } +} + +export function print_clip_colours() { + const api = new LiveAPI("live_set"); + const trackCount = api.getcount("tracks"); + log(`This live set has ${trackCount} tracks`); + + for (let trackIndex = 0; trackIndex < Math.min(8, trackCount); trackIndex++) { + api.goto(`live_set tracks ${trackIndex}`); + const clipSlotCount = api.getcount("clip_slots"); + log(`Track ${trackIndex + 1} has ${clipSlotCount} clip slots`); + + for ( + let clipSlotIndex = 0; + clipSlotIndex < Math.min(8, clipSlotCount); + clipSlotIndex++ + ) { + api.goto(`live_set tracks ${trackIndex} clip_slots ${clipSlotIndex}`); + + // returns a number array for some reason + const [hasClip] = api.get("has_clip"); + if (hasClip === 0) { + log( + `Clip slot ${clipSlotIndex + 1} in track ${trackIndex + 1} is empty`, + ); + continue; + } + api.goto( + `live_set tracks ${trackIndex} clip_slots ${clipSlotIndex} clip`, + ); + const colourIndex = api.get("color_index"); + log( + `Clip slot ${clipSlotIndex + 1} in track ${trackIndex + 1} has a clip with colour index ${colourIndex}`, + ); + } + } +} + +// function for testing colours on the launchpad +export function light_em_up(palette: number) { + let colourIndices = new Array(64).fill(0); + switch (palette) { + // palette 1 shows the launchpad colours in the order of their indices (1/2) + case 1: + colourIndices = colourIndices.map((_, index) => index); + break; + + // palette 2 shows the launchpad colours in the order of their indices (2/2) + case 2: + colourIndices = colourIndices.map((_, index) => index + 64); + break; + + // palette 3: custom assigment Live colours -> Launchpad colours (left side) + case 3: + colourIndices[0] = 56; // salmon + colourIndices[1] = 61; // frank orange + colourIndices[2] = 100; // dirty gold + colourIndices[3] = 73; // lemonade + colourIndices[4] = 85; // lime + colourIndices[5] = 87; // highlighter green + colourIndices[6] = 88; // bianchi + colourIndices[7] = 28; // turquoise + + colourIndices[8] = 106; // fire hydrant red + colourIndices[9] = 127; // tangerine + colourIndices[10] = 117; // sand + colourIndices[11] = 14; // sunshine yellow + colourIndices[12] = 86; // terminal green + colourIndices[13] = 19; // forest + colourIndices[14] = 65; // tiffany blue + colourIndices[15] = 68; // cyan + + colourIndices[16] = 105; // terracotta + colourIndices[17] = 107; // light salmon + colourIndices[18] = 8; // whiskey + colourIndices[19] = 73; // canary + colourIndices[20] = 113; // primrose + colourIndices[21] = 16; // wild willow + colourIndices[22] = 24; // dark sea green + colourIndices[23] = 114; // honeydew + + colourIndices[24] = 2; // dusty pink + colourIndices[25] = 105; // barley corn + colourIndices[26] = 118; // pale oyster; difficult + colourIndices[27] = 110; // dark khaki + colourIndices[28] = 18; // pistachio + colourIndices[29] = 102; // dollar bill + colourIndices[30] = 89; // neptune + colourIndices[31] = 89; // nepal + + colourIndices[32] = 121; // medium carmine + colourIndices[33] = 83; // red ochre + colourIndices[34] = 71; // coffee + colourIndices[35] = 15; // durian yellow + colourIndices[36] = 19; // pomelo green + colourIndices[37] = 27; // apple + colourIndices[38] = 65; // aquamarine + colourIndices[39] = 68; // sea blue + break; + + // palette 4: custom assigment Live colours -> Launchpad colours (right side) + case 4: + colourIndices[0] = 91; // sky blue + colourIndices[1] = 92; // sapphire + colourIndices[2] = 40; // periwinkle + colourIndices[3] = 82; // orchid + colourIndices[4] = 58; // magenta + colourIndices[5] = 3; // white + + colourIndices[8] = 39; // cerulean + colourIndices[9] = 43; // united nations blue + colourIndices[10] = 93; // amtethyst + colourIndices[11] = 70; // iris + colourIndices[12] = 53; // flamingo + colourIndices[13] = 2; // aluminum + + colourIndices[16] = 114; // pale turquoise + colourIndices[17] = 118; // periwinkle + colourIndices[18] = 2; // fog + colourIndices[19] = 39; // dull lavender + colourIndices[20] = 119; // whisper + colourIndices[21] = 118; // silver chalice + + colourIndices[24] = 36; // polo blue + colourIndices[25] = 40; // vista blue + colourIndices[26] = 2; // amethyst smoke + colourIndices[27] = 118; // lilac + colourIndices[28] = 70; // turkish rose + colourIndices[29] = 117; // steel + + colourIndices[32] = 104; // cosmic cobalt + colourIndices[33] = 112; // sapphire + colourIndices[34] = 71; // plump purple + colourIndices[35] = 70; // purpureus + colourIndices[36] = 55; // fuchsia rose + colourIndices[37] = 103; // eclipse + break; + + // palette 5: named colours from Novation palette + case 5: + colourIndices[0] = 0; // black + colourIndices[1] = 1; // dark grey / white half + colourIndices[2] = 2; // grey + colourIndices[3] = 3; // white + + colourIndices[8] = 8; // off white + colourIndices[9] = 12; // cream + + colourIndices[11] = 97; // yellow + colourIndices[12] = 125; // yellow half + + colourIndices[14] = 17; // dark yellow + colourIndices[15] = 19; // dark yellow half + + colourIndices[16] = 96; // amber + colourIndices[17] = 14; // amber half + + colourIndices[19] = 9; // orange + colourIndices[20] = 11; // orange half + + colourIndices[22] = 84; // dark orange + + colourIndices[24] = 5; // red + colourIndices[25] = 7; // red half + + colourIndices[32] = 53; // purple + colourIndices[33] = 55; // purple half + + colourIndices[35] = 52; // violet + + colourIndices[40] = 37; // light blue + colourIndices[41] = 39; // light blue half + + colourIndices[43] = 41; // blue + colourIndices[44] = 43; // blue half + + colourIndices[46] = 49; // dark blue + colourIndices[47] = 51; // dark blue half + + colourIndices[48] = 77; // aqua + + colourIndices[51] = 29; // mint + colourIndices[52] = 31; // mint half + + colourIndices[56] = 87; // pale green + colourIndices[57] = 89; // pale green half + + colourIndices[59] = 21; // green + colourIndices[60] = 27; // green half + break; + + // palette 6: hackable colours + case 6: + colourIndices[0] = 74; + colourIndices[1] = 84; + colourIndices[2] = 76; + colourIndices[3] = 69; + colourIndices[4] = 99; + colourIndices[5] = 19; + colourIndices[6] = 5; + colourIndices[7] = 71; + + colourIndices[8] = 15; + colourIndices[9] = 18; + colourIndices[10] = 11; + colourIndices[11] = 73; + colourIndices[12] = 58; + colourIndices[13] = 111; + colourIndices[14] = 13; + colourIndices[15] = 4; + + colourIndices[16] = 88; + colourIndices[17] = 65; + colourIndices[18] = 110; + colourIndices[19] = 46; + colourIndices[20] = 107; + colourIndices[21] = 102; + colourIndices[22] = 79; + colourIndices[23] = 117; + + colourIndices[24] = 119; + colourIndices[25] = 94; + colourIndices[26] = 44; + colourIndices[27] = 100; + colourIndices[28] = 78; + colourIndices[29] = 127; + colourIndices[30] = 96; + colourIndices[31] = 87; + + colourIndices[32] = 64; + colourIndices[33] = 90; + colourIndices[34] = 97; + colourIndices[35] = 126; + colourIndices[36] = 80; + colourIndices[37] = 10; + colourIndices[38] = 16; + colourIndices[39] = 105; + + colourIndices[40] = 14; + colourIndices[41] = 108; + colourIndices[42] = 70; + colourIndices[43] = 39; + colourIndices[44] = 47; + colourIndices[45] = 59; + colourIndices[46] = 121; + colourIndices[47] = 57; + + colourIndices[48] = 25; + colourIndices[49] = 112; + colourIndices[50] = 81; + colourIndices[51] = 8; + colourIndices[52] = 77; + colourIndices[53] = 93; + colourIndices[54] = 48; + colourIndices[55] = 43; + + colourIndices[56] = 103; + colourIndices[57] = 104; + colourIndices[58] = 55; + colourIndices[59] = 66; + colourIndices[60] = 95; + colourIndices[61] = 86; + colourIndices[62] = 28; + colourIndices[63] = 115; + + case 7: + colourIndices[0] = 116; + colourIndices[1] = 3; + colourIndices[2] = 33; + colourIndices[3] = 114; + } + let padIndex = 0; + for (let row = 80; row >= 10; row -= 10) { + for (let col = 1; col <= 8; col++) { + log(row, col, padIndex, colourIndices[padIndex]); + sendPadLightMidiMessage( + LightType.on, + row + col, + colourIndices[padIndex++], + ); + } + } +} + +function getTrackIndex(trackToFind: any) { + const liveSet = new LiveAPI("live_set"); + const trackCount = liveSet.getcount("tracks"); + + for (let i = 0; i < trackCount; i++) { + const track = new LiveAPI(`live_set tracks ${i}`); + if (track.id === trackToFind.id) { + return i; + } + } + return null; +} + +function getSelectedTrackIndex() { + const selectedTrack = new LiveAPI("live_set view selected_track"); + return getTrackIndex(selectedTrack); +} + +function observeSelectedTrack( + callback: (prevTrackIndex: number | null, trackIndex: number | null) => void, +) { + let prevTrackIndex: number | null = null; + const songView = new LiveAPI((value: any) => { + if (value.length !== 3 || value[0] !== "selected_track") { + return; + } + const id: Id = value.slice(1); + const track = new LiveAPI(id); + const [trackName] = track.get("name"); + const trackIndex = getTrackIndex(track); + log("selected track:", trackName, trackIndex); + callback(prevTrackIndex, trackIndex); + prevTrackIndex = trackIndex; + }, "live_set view"); + songView.property = "selected_track"; +} + +function sendPadLightMidiMessage( + lightType: LightType, + position: number, + colourIndex?: number, +) { + switch (lightType) { + case LightType.on: + outlet(0, [144, position, colourIndex]); + break; + case LightType.blink: + outlet(0, [144, position, 0]); + outlet(1, [145, position, colourIndex]); + break; + case LightType.pulse: + outlet(2, [146, position, colourIndex]); + break; + case LightType.off: + outlet(0, [144, position, 0]); + break; + } +} diff --git a/src/objects/betterLaunchpadColoursPlayground/index.ts b/src/objects/betterLaunchpadColoursPlayground/index.ts new file mode 100644 index 0000000..9d5b838 --- /dev/null +++ b/src/objects/betterLaunchpadColoursPlayground/index.ts @@ -0,0 +1 @@ +export * from "./betterLaunchpadColoursPlayground"; diff --git a/src/polyfills/fill.ts b/src/polyfills/fill.ts new file mode 100644 index 0000000..1e1dedc --- /dev/null +++ b/src/polyfills/fill.ts @@ -0,0 +1,23 @@ +// @ts-nocheck +Array.prototype.fill = function (value) { + var O = Object(this); + var len = parseInt(O.length, 10); + var start = arguments[1]; + var relativeStart = parseInt(start, 10) || 0; + var k = + relativeStart < 0 + ? Math.max(len + relativeStart, 0) + : Math.min(relativeStart, len); + var end = arguments[2]; + var relativeEnd = end === undefined ? len : parseInt(end) || 0; + var final = + relativeEnd < 0 + ? Math.max(len + relativeEnd, 0) + : Math.min(relativeEnd, len); + + for (; k < final; k++) { + O[k] = value; + } + + return O; +}; diff --git a/src/util/ApiManager.ts b/src/util/ApiManager.ts new file mode 100644 index 0000000..f9e2544 --- /dev/null +++ b/src/util/ApiManager.ts @@ -0,0 +1,66 @@ +import log from "./log"; +import ManagedApi from "./ManagedApi"; + +export default class ApiManager { + private _apis: Record = {}; + + make(id: string, callback: (...args: any[]) => void) { + const tokens = id.split(" "); + const property = tokens[tokens.length - 1]; + const path = tokens.slice(0, tokens.length - 1).join(" "); + const api = new LiveAPI((message: [string, number]) => { + const [type, value] = message; + if (type === property) { + callback(value); + return; + } + }, path); + const managedApi = new ManagedApi(id, api, this); + this._apis[id] = managedApi; + managedApi.property = property; + return managedApi; + } + + add( + parent: ManagedApi | string, + id: string, + callback: (...args: any[]) => void, + ) { + let finalParent: ManagedApi; + if (typeof parent === "string") { + finalParent = this._apis[id]; + if (!finalParent) { + return; + } + } else { + finalParent = parent; + } + finalParent.add(id, callback); + return finalParent; + } + + kill(id: string) { + const api = this._apis[id]; + if (!api) { + return; + } + api.stop(); + delete this._apis[id]; + } + + start(id: string) { + const api = this._apis[id]; + if (!api) { + return; + } + api.start(); + } + + stop(id: string) { + const api = this._apis[id]; + if (!api) { + return; + } + api.stop(); + } +} diff --git a/src/util/ManagedApi.ts b/src/util/ManagedApi.ts new file mode 100644 index 0000000..22edbaa --- /dev/null +++ b/src/util/ManagedApi.ts @@ -0,0 +1,57 @@ +import log from "./log"; +import type ApiManager from "./ApiManager"; + +export default class ManagedApi { + private _id: string; + private _api: LiveAPI; + private _apiMan: ApiManager; + private _children: string[] = []; + private _property: string = ""; + + constructor(id: string, api: LiveAPI, apiMan: ApiManager) { + this._id = id; + this._api = api; + this._apiMan = apiMan; + } + + set property(value: string) { + this._property = value; + } + + start() { + this._api.property = this._property; + this.startChildren(); + } + + startChildren() { + this._children.forEach((id) => this._apiMan.start(id)); + } + + stop() { + this._api.property = ""; + this.stopChildren(); + } + + stopChildren() { + this._children.forEach((id) => this._apiMan.stop(id)); + } + + kill() { + this._apiMan.kill(this._id); + this.killChildren(); + } + + killChildren() { + this._children.forEach((id) => this._apiMan.kill(id)); + this._children = []; + } + + add(id: string, callback: (...args: any[]) => void) { + if (this._children.includes(id)) { + return; + } + const managedApi = this._apiMan.make(id, callback); + this._children.push(id); + return managedApi; + } +} diff --git a/src/util/getCount.ts b/src/util/getCount.ts new file mode 100644 index 0000000..e45002f --- /dev/null +++ b/src/util/getCount.ts @@ -0,0 +1,6 @@ +export default function getCount(id: string) { + const tokens = id.split(" "); + const property = tokens[tokens.length - 1]; + const path = tokens.slice(0, tokens.length - 1).join(" "); + return new LiveAPI(path).getcount(property); +} diff --git a/src/util/index.ts b/src/util/index.ts index 834d5d7..6943b05 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,6 +1,9 @@ +export { default as ApiManager } from "./ApiManager"; +export { default as ManagedApi } from "./ManagedApi"; export { default as convertStringNumberArrayToIds } from "./convertStringNumberArrayToIds"; export { default as getControlSurfaceId } from "./getControlSurfaceId"; export { default as getControlSurfaceNames } from "./getControlSurfaceNames"; +export { default as getCount } from "./getCount"; export { default as getLiveTrackIndex } from "./getLiveTrackIndex"; export { default as getNumberProperty } from "./getNumberProperty"; export { default as getObjectById } from "./getObjectById"; diff --git a/webpack.config.js b/webpack.config.js index 3e87752..2be6f9a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -31,7 +31,7 @@ module.exports = { ], }, resolve: { - extensions: [".ts"], + extensions: [".ts", ".js"], }, optimization: { minimize: false, diff --git a/yarn.lock b/yarn.lock index 954de20..9d33d5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,6 +64,13 @@ __metadata: languageName: node linkType: hard +"@types/core-js@npm:^2.5.8": + version: 2.5.8 + resolution: "@types/core-js@npm:2.5.8" + checksum: 10/58c4b86102b13b778d3631d38913c788ef7f688d99fbd741f6241a9cedc7e986e670011bdccd58b32e28e97b9c0fa6fffedef6ba0f670a005b321788a5a01a65 + languageName: node + linkType: hard + "@types/estree@npm:^1.0.5": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" @@ -435,6 +442,13 @@ __metadata: languageName: node linkType: hard +"core-js@npm:^3.39.0": + version: 3.39.0 + resolution: "core-js@npm:3.39.0" + checksum: 10/a3d34e669783dfc878e545f1983f60d9ff48a3867cd1d7ff8839b849e053002a208c7c14a5ca354b8e0b54982901e2f83dc87c3d9b95de0a94b4071d1c74e5f6 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -736,6 +750,8 @@ __metadata: version: 0.0.0-use.local resolution: "max-for-live-lib@workspace:." dependencies: + "@types/core-js": "npm:^2.5.8" + core-js: "npm:^3.39.0" dotenv: "npm:^8.2.0" prettier: "npm:^3.3.3" ts-loader: "npm:^9.5.1"