ableton-js 3.4.6 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +9 -2
- package/index.d.ts +8 -3
- package/index.js +37 -20
- package/midi-script/AbletonJS.py +5 -1
- package/midi-script/Session.py +42 -0
- package/midi-script/Socket.py +14 -10
- package/midi-script/version.py +1 -1
- package/ns/browser-item.d.ts +11 -11
- package/ns/browser.d.ts +1 -1
- package/ns/clip-slot.d.ts +6 -6
- package/ns/clip.d.ts +9 -9
- package/ns/cue-point.d.ts +3 -3
- package/ns/device-parameter.d.ts +4 -4
- package/ns/device.d.ts +4 -4
- package/ns/index.d.ts +1 -1
- package/ns/index.js +2 -2
- package/ns/scene.d.ts +3 -3
- package/ns/session.d.ts +15 -0
- package/ns/session.js +19 -0
- package/ns/track.d.ts +9 -9
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [v3.6.0](https://github.com/leolabs/ableton.js/compare/v3.5.0...v3.6.0)
|
|
8
|
+
|
|
9
|
+
- :label: Mark all raw object state as readonly [`ace0efd`](https://github.com/leolabs/ableton.js/commit/ace0efde39e5b598dd0a2878e0e29ecffedd495a)
|
|
10
|
+
- :sparkles: Add options to override the caching mechanism [`85405d4`](https://github.com/leolabs/ableton.js/commit/85405d4be89bdc052f53bb862c5fe904620c554a)
|
|
11
|
+
|
|
12
|
+
#### [v3.5.0](https://github.com/leolabs/ableton.js/compare/v3.4.6...v3.5.0)
|
|
13
|
+
|
|
14
|
+
> 10 November 2024
|
|
15
|
+
|
|
16
|
+
- Feature: session highlighting with red ring [`#123`](https://github.com/leolabs/ableton.js/pull/123)
|
|
17
|
+
- Update README to have correct start scripts [`#124`](https://github.com/leolabs/ableton.js/pull/124)
|
|
18
|
+
- :hammer: Add a `format` command and document it in the readme [`b383e44`](https://github.com/leolabs/ableton.js/commit/b383e449692f2c2741fbbd013c87c055716a34e2)
|
|
19
|
+
- :bug: Fix large messages sent by the Python script not being received processed properly by Node [`fd33ce3`](https://github.com/leolabs/ableton.js/commit/fd33ce305521b580f2c87ef72034225e5feaf14d)
|
|
20
|
+
- :bug: Fix larger messages not being received properly in Live [`233296e`](https://github.com/leolabs/ableton.js/commit/233296e054b80b961b5011ebbe1b849cd3cbbd22)
|
|
21
|
+
- :bug: Fix typing for `mute` value [`30f62ee`](https://github.com/leolabs/ableton.js/commit/30f62ee0195a03bdc4bd48e9b0c2ee5a120212d4)
|
|
22
|
+
|
|
7
23
|
#### [v3.4.6](https://github.com/leolabs/ableton.js/compare/v3.4.5...v3.4.6)
|
|
8
24
|
|
|
25
|
+
> 18 May 2024
|
|
26
|
+
|
|
9
27
|
- Get `song.view.get('detail_clip')` working [`#118`](https://github.com/leolabs/ableton.js/pull/118)
|
|
10
28
|
|
|
11
29
|
#### [v3.4.5](https://github.com/leolabs/ableton.js/compare/v3.4.4...v3.4.5)
|
package/README.md
CHANGED
|
@@ -31,8 +31,9 @@ After starting Ableton Live, add the script to your list of control surfaces:
|
|
|
31
31
|

|
|
32
32
|
|
|
33
33
|
If you've forked this project on macOS, you can also use yarn to do that for
|
|
34
|
-
you. Running `yarn
|
|
35
|
-
|
|
34
|
+
you. Running `yarn ableton10:start` or `yarn ableton11:start` (depending on your
|
|
35
|
+
app version) will copy the `midi-script` folder, open Ableton and show a stream
|
|
36
|
+
of log messages until you kill it.
|
|
36
37
|
|
|
37
38
|
## Using Ableton.js
|
|
38
39
|
|
|
@@ -240,3 +241,9 @@ library.
|
|
|
240
241
|
[Issue #4](https://github.com/leolabs/ableton-js/issues/4)
|
|
241
242
|
- The `playing_status` listener of clip slots never fires in Ableton. See
|
|
242
243
|
[Issue #25](https://github.com/leolabs/ableton-js/issues/25)
|
|
244
|
+
|
|
245
|
+
## Contributing
|
|
246
|
+
|
|
247
|
+
If you'd like to add features to this project or submit a bugfix, please feel
|
|
248
|
+
free to open a pull request. Before committing changes to any of the TypeScript
|
|
249
|
+
files, please run `yarn format` to format the code using Prettier.
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { EventEmitter } from "events";
|
|
3
2
|
import LruCache from "lru-cache";
|
|
4
3
|
import { Song } from "./ns/song";
|
|
@@ -7,6 +6,7 @@ import { Application } from "./ns/application";
|
|
|
7
6
|
import { Midi } from "./ns/midi";
|
|
8
7
|
import { Cache } from "./util/cache";
|
|
9
8
|
import { Logger } from "./util/logger";
|
|
9
|
+
import { Session } from "./ns/session";
|
|
10
10
|
interface Command {
|
|
11
11
|
uuid: string;
|
|
12
12
|
ns: string;
|
|
@@ -82,6 +82,10 @@ export interface AbletonOptions {
|
|
|
82
82
|
* Options for the response cache.
|
|
83
83
|
*/
|
|
84
84
|
cacheOptions?: LruCache.Options<string, any>;
|
|
85
|
+
/**
|
|
86
|
+
* Completely disables the cache.
|
|
87
|
+
*/
|
|
88
|
+
disableCache?: boolean;
|
|
85
89
|
/**
|
|
86
90
|
* Set this to allow ableton-js to log messages. If you set this to
|
|
87
91
|
* `console`, log messages are printed to the standard output.
|
|
@@ -98,8 +102,9 @@ export declare class Ableton extends EventEmitter implements ConnectionEventEmit
|
|
|
98
102
|
private buffer;
|
|
99
103
|
private latency;
|
|
100
104
|
private serverPort;
|
|
101
|
-
cache
|
|
105
|
+
cache?: Cache;
|
|
102
106
|
song: Song;
|
|
107
|
+
session: Session;
|
|
103
108
|
application: Application;
|
|
104
109
|
internal: Internal;
|
|
105
110
|
midi: Midi;
|
|
@@ -150,7 +155,7 @@ export declare class Ableton extends EventEmitter implements ConnectionEventEmit
|
|
|
150
155
|
* disconnects, for example.
|
|
151
156
|
*/
|
|
152
157
|
removeAllPropListeners(): void;
|
|
153
|
-
sendRaw(msg: string): void
|
|
158
|
+
sendRaw(msg: string): Promise<void>;
|
|
154
159
|
isConnected(): boolean;
|
|
155
160
|
}
|
|
156
161
|
export { getPackageVersion } from "./util/package-version";
|
package/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const application_1 = require("./ns/application");
|
|
|
21
21
|
const midi_1 = require("./ns/midi");
|
|
22
22
|
const package_version_1 = require("./util/package-version");
|
|
23
23
|
const cache_1 = require("./util/cache");
|
|
24
|
+
const session_1 = require("./ns/session");
|
|
24
25
|
const SERVER_PORT_FILE = "ableton-js-server.port";
|
|
25
26
|
const CLIENT_PORT_FILE = "ableton-js-client.port";
|
|
26
27
|
class TimeoutError extends Error {
|
|
@@ -55,6 +56,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
55
56
|
serverPort;
|
|
56
57
|
cache;
|
|
57
58
|
song = new song_1.Song(this);
|
|
59
|
+
session = new session_1.Session(this); // added for red session ring control
|
|
58
60
|
application = new application_1.Application(this);
|
|
59
61
|
internal = new internal_1.Internal(this);
|
|
60
62
|
midi = new midi_1.Midi(this);
|
|
@@ -67,11 +69,13 @@ class Ableton extends events_1.EventEmitter {
|
|
|
67
69
|
super();
|
|
68
70
|
this.options = options;
|
|
69
71
|
this.logger = options?.logger;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
if (!options?.disableCache) {
|
|
73
|
+
this.cache = new lru_cache_1.default({
|
|
74
|
+
max: 500,
|
|
75
|
+
ttl: 1000 * 60 * 10,
|
|
76
|
+
...options?.cacheOptions,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
75
79
|
this.clientPortFile = path_1.default.join(os_1.default.tmpdir(), this.options?.clientPortFile ?? CLIENT_PORT_FILE);
|
|
76
80
|
this.serverPortFile = path_1.default.join(os_1.default.tmpdir(), this.options?.serverPortFile ?? SERVER_PORT_FILE);
|
|
77
81
|
}
|
|
@@ -124,7 +128,9 @@ class Ableton extends events_1.EventEmitter {
|
|
|
124
128
|
return this.waitForConnection();
|
|
125
129
|
}
|
|
126
130
|
this.clientState = "starting";
|
|
127
|
-
|
|
131
|
+
// The recvBufferSize is set to macOS' default value, so the
|
|
132
|
+
// socket behaves the same on Windows and doesn't drop any packets
|
|
133
|
+
this.client = dgram_1.default.createSocket({ type: "udp4", recvBufferSize: 786896 });
|
|
128
134
|
this.client.addListener("message", this.handleIncoming.bind(this));
|
|
129
135
|
this.client.addListener("listening", async () => {
|
|
130
136
|
const port = this.client?.address().port;
|
|
@@ -256,18 +262,26 @@ class Ableton extends events_1.EventEmitter {
|
|
|
256
262
|
}
|
|
257
263
|
handleIncoming(msg, info) {
|
|
258
264
|
try {
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (
|
|
264
|
-
this.handleUncompressedMessage((0, zlib_1.unzipSync)(
|
|
265
|
-
|
|
265
|
+
const messageId = msg[0];
|
|
266
|
+
const messageIndex = msg[1];
|
|
267
|
+
const totalMessages = msg[2];
|
|
268
|
+
const message = msg.subarray(3);
|
|
269
|
+
if (messageIndex === 0 && totalMessages === 1) {
|
|
270
|
+
this.handleUncompressedMessage((0, zlib_1.unzipSync)(message).toString());
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (!this.buffer[messageId]) {
|
|
274
|
+
this.buffer[messageId] = [];
|
|
275
|
+
}
|
|
276
|
+
this.buffer[messageId][messageIndex] = message;
|
|
277
|
+
if (!this.buffer[messageId].includes(undefined) &&
|
|
278
|
+
this.buffer[messageId].length === totalMessages) {
|
|
279
|
+
this.handleUncompressedMessage((0, zlib_1.unzipSync)(Buffer.concat(this.buffer[messageId])).toString());
|
|
280
|
+
delete this.buffer[messageId];
|
|
266
281
|
}
|
|
267
282
|
}
|
|
268
283
|
catch (e) {
|
|
269
284
|
this.buffer = [];
|
|
270
|
-
this.logger?.warn("Couldn't handle message:", { error: e });
|
|
271
285
|
this.emit("error", e);
|
|
272
286
|
}
|
|
273
287
|
}
|
|
@@ -353,7 +367,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
353
367
|
async sendCachedCommand(command) {
|
|
354
368
|
const args = command.args?.prop ?? JSON.stringify(command.args);
|
|
355
369
|
const cacheKey = [command.ns, command.nsid, args].filter(Boolean).join("/");
|
|
356
|
-
const cached = this.cache
|
|
370
|
+
const cached = this.cache?.get(cacheKey);
|
|
357
371
|
const result = await this.sendCommand({
|
|
358
372
|
...command,
|
|
359
373
|
etag: cached?.etag,
|
|
@@ -369,14 +383,14 @@ class Ableton extends events_1.EventEmitter {
|
|
|
369
383
|
}
|
|
370
384
|
else {
|
|
371
385
|
if (result.etag) {
|
|
372
|
-
this.cache
|
|
386
|
+
this.cache?.set(cacheKey, result);
|
|
373
387
|
}
|
|
374
388
|
return result.data;
|
|
375
389
|
}
|
|
376
390
|
}
|
|
377
391
|
async getProp(ns, nsid, prop, cache) {
|
|
378
392
|
const params = { ns, nsid, name: "get_prop", args: { prop } };
|
|
379
|
-
if (cache) {
|
|
393
|
+
if (cache && this.cache) {
|
|
380
394
|
return this.sendCachedCommand(params);
|
|
381
395
|
}
|
|
382
396
|
else {
|
|
@@ -438,21 +452,24 @@ class Ableton extends events_1.EventEmitter {
|
|
|
438
452
|
removeAllPropListeners() {
|
|
439
453
|
this.eventListeners.clear();
|
|
440
454
|
}
|
|
441
|
-
sendRaw(msg) {
|
|
455
|
+
async sendRaw(msg) {
|
|
442
456
|
if (!this.client || !this.serverPort) {
|
|
443
457
|
throw new Error("The client hasn't been started yet. Please call start() first.");
|
|
444
458
|
}
|
|
445
459
|
const buffer = (0, zlib_1.deflateSync)(Buffer.from(msg));
|
|
446
|
-
const byteLimit = this.client.getSendBufferSize() -
|
|
460
|
+
const byteLimit = this.client.getSendBufferSize() - 100;
|
|
447
461
|
const chunks = Math.ceil(buffer.byteLength / byteLimit);
|
|
448
462
|
// Split the message into chunks if it becomes too large
|
|
449
463
|
for (let i = 0; i < chunks; i++) {
|
|
450
464
|
const chunk = Buffer.concat([
|
|
451
465
|
// Add a counter to the message, the last message is always 255
|
|
452
466
|
Buffer.alloc(1, i + 1 === chunks ? 255 : i),
|
|
453
|
-
buffer.
|
|
467
|
+
buffer.subarray(i * byteLimit, i * byteLimit + byteLimit),
|
|
454
468
|
]);
|
|
455
469
|
this.client.send(chunk, 0, chunk.length, this.serverPort, "127.0.0.1");
|
|
470
|
+
// Add a bit of a delay between sent chunks to reduce the chance of the
|
|
471
|
+
// receiving buffer filling up which would cause chunks to be discarded.
|
|
472
|
+
await new Promise((res) => setTimeout(res, 20));
|
|
456
473
|
}
|
|
457
474
|
}
|
|
458
475
|
isConnected() {
|
package/midi-script/AbletonJS.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
import time
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
from .version import version
|
|
6
5
|
from .Config import DEBUG, FAST_POLLING
|
|
7
6
|
from .Logging import logger
|
|
8
7
|
from .Socket import Socket
|
|
9
8
|
from .Interface import Interface
|
|
10
9
|
from .Application import Application
|
|
10
|
+
from .Session import Session
|
|
11
11
|
from .ApplicationView import ApplicationView
|
|
12
12
|
from .Browser import Browser
|
|
13
13
|
from .BrowserItem import BrowserItem
|
|
@@ -32,6 +32,7 @@ import Live
|
|
|
32
32
|
class AbletonJS(ControlSurface):
|
|
33
33
|
def __init__(self, c_instance):
|
|
34
34
|
super(AbletonJS, self).__init__(c_instance)
|
|
35
|
+
|
|
35
36
|
logger.info("Starting AbletonJS " + version + "...")
|
|
36
37
|
|
|
37
38
|
self.tracked_midi = set()
|
|
@@ -42,6 +43,8 @@ class AbletonJS(ControlSurface):
|
|
|
42
43
|
self.handlers = {
|
|
43
44
|
"application": Application(c_instance, self.socket, self.application()),
|
|
44
45
|
"application-view": ApplicationView(c_instance, self.socket, self.application()),
|
|
46
|
+
# added for red box control
|
|
47
|
+
"session": Session(c_instance, self.socket, self),
|
|
45
48
|
"browser": Browser(c_instance, self.socket, self.application()),
|
|
46
49
|
"browser-item": BrowserItem(c_instance, self.socket),
|
|
47
50
|
"cue-point": CuePoint(c_instance, self.socket),
|
|
@@ -109,6 +112,7 @@ class AbletonJS(ControlSurface):
|
|
|
109
112
|
super(AbletonJS, self).disconnect()
|
|
110
113
|
|
|
111
114
|
def command_handler(self, payload):
|
|
115
|
+
|
|
112
116
|
namespace = payload["ns"]
|
|
113
117
|
|
|
114
118
|
# Don't clutter the logs
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
from .Interface import Interface
|
|
3
|
+
from .Logging import logger
|
|
4
|
+
|
|
5
|
+
from _Framework.SessionComponent import SessionComponent
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Session(Interface):
|
|
9
|
+
def __init__(self, c_instance, socket, controlSurface):
|
|
10
|
+
super(Session, self).__init__(c_instance, socket)
|
|
11
|
+
|
|
12
|
+
self.controlSurface = controlSurface
|
|
13
|
+
self.sessionComponent = SessionComponent
|
|
14
|
+
|
|
15
|
+
def get_ns(self, nsid=None):
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
def setup_session_box(self, ns, num_tracks=2, num_scenes=2):
|
|
19
|
+
"""
|
|
20
|
+
Creates the session with the red ring box.
|
|
21
|
+
"""
|
|
22
|
+
with self.controlSurface.component_guard():
|
|
23
|
+
logger.info(
|
|
24
|
+
f"Setting up session box with {num_tracks} tracks and {num_scenes} scenes.")
|
|
25
|
+
self.session = self.sessionComponent(num_tracks, num_scenes)
|
|
26
|
+
self.session.set_offsets(0, 0)
|
|
27
|
+
self.controlSurface.set_highlighting_session_component(
|
|
28
|
+
self.session)
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
def set_session_offset(self, ns, track_offset, scene_offset):
|
|
32
|
+
"""
|
|
33
|
+
Sets the offset of the SessionComponent instance.
|
|
34
|
+
"""
|
|
35
|
+
logger.info(
|
|
36
|
+
f"Moving session box offset to {track_offset} and {scene_offset}.")
|
|
37
|
+
|
|
38
|
+
if hasattr(self, 'session'):
|
|
39
|
+
self.session.set_offsets(track_offset, scene_offset)
|
|
40
|
+
else:
|
|
41
|
+
logger.error("Session box not set up.")
|
|
42
|
+
return True
|
package/midi-script/Socket.py
CHANGED
|
@@ -36,6 +36,8 @@ class Socket(object):
|
|
|
36
36
|
self._last_error = ""
|
|
37
37
|
self._socket = None
|
|
38
38
|
self._chunk_limit = None
|
|
39
|
+
self._message_id = 0
|
|
40
|
+
self._receive_buffer = bytearray()
|
|
39
41
|
|
|
40
42
|
self.read_remote_port()
|
|
41
43
|
self.init_socket(True)
|
|
@@ -154,14 +156,19 @@ class Socket(object):
|
|
|
154
156
|
if self._socket == None or self._chunk_limit == None:
|
|
155
157
|
return
|
|
156
158
|
|
|
159
|
+
self._message_id = (self._message_id + 1) % 256
|
|
160
|
+
message_id_byte = struct.pack("B", self._message_id)
|
|
161
|
+
|
|
157
162
|
if len(compressed) < self._chunk_limit:
|
|
158
|
-
self._socket.sendto(b'\
|
|
163
|
+
self._socket.sendto(message_id_byte + b'\x00\x01' + compressed, self._client_addr)
|
|
159
164
|
else:
|
|
160
165
|
chunks = list(split_by_n(compressed, self._chunk_limit))
|
|
161
166
|
count = len(chunks)
|
|
167
|
+
count_byte = struct.pack("B", count)
|
|
162
168
|
for i, chunk in enumerate(chunks):
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
logger.info("Sending packet " + str(self._message_id) + " - " + str(i) + "/" + str(count))
|
|
170
|
+
packet_byte = struct.pack("B", i)
|
|
171
|
+
self._socket.sendto(message_id_byte + packet_byte + count_byte + chunk, self._client_addr)
|
|
165
172
|
|
|
166
173
|
def send(self, name, obj=None, uuid=None):
|
|
167
174
|
def jsonReplace(o):
|
|
@@ -189,21 +196,18 @@ class Socket(object):
|
|
|
189
196
|
|
|
190
197
|
def process(self):
|
|
191
198
|
try:
|
|
192
|
-
buffer = bytes()
|
|
193
|
-
num_messages = 0
|
|
194
199
|
while 1:
|
|
195
200
|
data = self._socket.recv(65536)
|
|
196
201
|
if len(data) and self.input_handler:
|
|
197
|
-
|
|
198
|
-
num_messages += 1
|
|
202
|
+
self._receive_buffer.extend(data[1:])
|
|
199
203
|
|
|
200
204
|
# \xFF for Live 10 (Python2) and 255 for Live 11 (Python3)
|
|
201
205
|
if (data[0] == b'\xFF' or data[0] == 255):
|
|
202
|
-
|
|
206
|
+
packet = self._receive_buffer
|
|
207
|
+
self._receive_buffer = bytearray()
|
|
208
|
+
unzipped = zlib.decompress(packet)
|
|
203
209
|
payload = json.loads(unzipped)
|
|
204
210
|
self.input_handler(payload)
|
|
205
|
-
buffer = bytes()
|
|
206
|
-
num_messages = 0
|
|
207
211
|
|
|
208
212
|
except socket.error as e:
|
|
209
213
|
if (e.errno != 35 and e.errno != 10035 and e.errno != 10054):
|
package/midi-script/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "3.
|
|
1
|
+
version = "3.6.0"
|
package/ns/browser-item.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import { Ableton } from "..";
|
|
2
2
|
import { Namespace } from ".";
|
|
3
|
-
export interface RawBrowserItem {
|
|
4
|
-
id: string;
|
|
5
|
-
children: RawBrowserItem[];
|
|
6
|
-
name: string;
|
|
7
|
-
is_loadable: boolean;
|
|
8
|
-
is_selected: boolean;
|
|
9
|
-
is_device: boolean;
|
|
10
|
-
is_folder: boolean;
|
|
11
|
-
source: string;
|
|
12
|
-
uri: string;
|
|
13
|
-
}
|
|
14
3
|
export interface GettableProperties {
|
|
15
4
|
children: RawBrowserItem[];
|
|
16
5
|
is_device: boolean;
|
|
@@ -28,6 +17,17 @@ export interface SettableProperties {
|
|
|
28
17
|
}
|
|
29
18
|
export interface ObservableProperties {
|
|
30
19
|
}
|
|
20
|
+
export interface RawBrowserItem {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly children: RawBrowserItem[];
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly is_loadable: boolean;
|
|
25
|
+
readonly is_selected: boolean;
|
|
26
|
+
readonly is_device: boolean;
|
|
27
|
+
readonly is_folder: boolean;
|
|
28
|
+
readonly source: string;
|
|
29
|
+
readonly uri: string;
|
|
30
|
+
}
|
|
31
31
|
export declare class BrowserItem extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
32
32
|
raw: RawBrowserItem;
|
|
33
33
|
constructor(ableton: Ableton, raw: RawBrowserItem);
|
package/ns/browser.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface ObservableProperties {
|
|
|
42
42
|
hotswap_target: BrowserItem;
|
|
43
43
|
}
|
|
44
44
|
export interface RawBrowser {
|
|
45
|
-
id: string;
|
|
45
|
+
readonly id: string;
|
|
46
46
|
}
|
|
47
47
|
export declare class Browser extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
48
48
|
constructor(ableton: Ableton);
|
package/ns/clip-slot.d.ts
CHANGED
|
@@ -39,12 +39,12 @@ export interface ObservableProperties {
|
|
|
39
39
|
playing_status: PlayingStatus;
|
|
40
40
|
}
|
|
41
41
|
export interface RawClipSlot {
|
|
42
|
-
id: string;
|
|
43
|
-
color: number;
|
|
44
|
-
has_clip: boolean;
|
|
45
|
-
is_playing: boolean;
|
|
46
|
-
is_recording: boolean;
|
|
47
|
-
is_triggered: boolean;
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly color: number;
|
|
44
|
+
readonly has_clip: boolean;
|
|
45
|
+
readonly is_playing: boolean;
|
|
46
|
+
readonly is_recording: boolean;
|
|
47
|
+
readonly is_triggered: boolean;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* This class represents an entry in Live's Session view matrix.
|
package/ns/clip.d.ts
CHANGED
|
@@ -135,15 +135,15 @@ export interface ObservableProperties {
|
|
|
135
135
|
warping: boolean;
|
|
136
136
|
}
|
|
137
137
|
export interface RawClip {
|
|
138
|
-
id: string;
|
|
139
|
-
name: string;
|
|
140
|
-
color: number;
|
|
141
|
-
color_index: number;
|
|
142
|
-
is_audio_clip: boolean;
|
|
143
|
-
is_midi_clip: boolean;
|
|
144
|
-
start_time: number;
|
|
145
|
-
end_time: number;
|
|
146
|
-
muted: boolean;
|
|
138
|
+
readonly id: string;
|
|
139
|
+
readonly name: string;
|
|
140
|
+
readonly color: number;
|
|
141
|
+
readonly color_index: number;
|
|
142
|
+
readonly is_audio_clip: boolean;
|
|
143
|
+
readonly is_midi_clip: boolean;
|
|
144
|
+
readonly start_time: number;
|
|
145
|
+
readonly end_time: number;
|
|
146
|
+
readonly muted: boolean;
|
|
147
147
|
}
|
|
148
148
|
/**
|
|
149
149
|
* This class represents an entry in Live's Session view matrix.
|
package/ns/cue-point.d.ts
CHANGED
|
@@ -13,9 +13,9 @@ export interface ObservableProperties {
|
|
|
13
13
|
time: number;
|
|
14
14
|
}
|
|
15
15
|
export interface RawCuePoint {
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
time: number;
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly time: number;
|
|
19
19
|
}
|
|
20
20
|
export declare class CuePoint extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
21
21
|
raw: RawCuePoint;
|
package/ns/device-parameter.d.ts
CHANGED
|
@@ -25,10 +25,10 @@ export interface ObservableProperties {
|
|
|
25
25
|
value: number;
|
|
26
26
|
}
|
|
27
27
|
export interface RawDeviceParameter {
|
|
28
|
-
id: string;
|
|
29
|
-
name: string;
|
|
30
|
-
value: number;
|
|
31
|
-
is_quantized: boolean;
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly value: number;
|
|
31
|
+
readonly is_quantized: boolean;
|
|
32
32
|
}
|
|
33
33
|
export declare enum AutomationState {
|
|
34
34
|
None = 0,
|
package/ns/device.d.ts
CHANGED
|
@@ -23,10 +23,10 @@ export interface ObservableProperties {
|
|
|
23
23
|
parameters: string;
|
|
24
24
|
}
|
|
25
25
|
export interface RawDevice {
|
|
26
|
-
id: string;
|
|
27
|
-
name: string;
|
|
28
|
-
type: DeviceType;
|
|
29
|
-
class_name: string;
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly type: DeviceType;
|
|
29
|
+
readonly class_name: string;
|
|
30
30
|
}
|
|
31
31
|
export declare enum DeviceType {
|
|
32
32
|
AudioEffect = "audio_effect",
|
package/ns/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare class Namespace<GP, TP, SP, OP> {
|
|
|
10
10
|
[T in keyof GP]: boolean;
|
|
11
11
|
}>;
|
|
12
12
|
constructor(ableton: Ableton, ns: string, nsid?: string | undefined);
|
|
13
|
-
get<T extends keyof GP>(prop: T): Promise<T extends keyof TP ? TP[T] : GP[T]>;
|
|
13
|
+
get<T extends keyof GP>(prop: T, useCache?: boolean): Promise<T extends keyof TP ? TP[T] : GP[T]>;
|
|
14
14
|
set<T extends keyof SP>(prop: T, value: SP[T]): Promise<null>;
|
|
15
15
|
addListener<T extends keyof OP>(prop: T, listener: (data: T extends keyof TP ? TP[T] : OP[T]) => any): Promise<() => Promise<boolean | undefined>>;
|
|
16
16
|
/**
|
package/ns/index.js
CHANGED
|
@@ -12,8 +12,8 @@ class Namespace {
|
|
|
12
12
|
this.ns = ns;
|
|
13
13
|
this.nsid = nsid;
|
|
14
14
|
}
|
|
15
|
-
async get(prop) {
|
|
16
|
-
const cache = !!this.cachedProps[prop];
|
|
15
|
+
async get(prop, useCache) {
|
|
16
|
+
const cache = useCache ?? !!this.cachedProps[prop];
|
|
17
17
|
const res = await this.ableton.getProp(this.ns, this.nsid, String(prop), cache);
|
|
18
18
|
const transformer = this.transformers[prop];
|
|
19
19
|
if (res !== null && transformer) {
|
package/ns/scene.d.ts
CHANGED
|
@@ -30,9 +30,9 @@ export interface ObservableProperties {
|
|
|
30
30
|
name: string;
|
|
31
31
|
}
|
|
32
32
|
export interface RawScene {
|
|
33
|
-
color: number;
|
|
34
|
-
id: string;
|
|
35
|
-
name: string;
|
|
33
|
+
readonly color: number;
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly name: string;
|
|
36
36
|
}
|
|
37
37
|
export declare class Scene extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
38
38
|
raw: RawScene;
|
package/ns/session.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Ableton } from "..";
|
|
2
|
+
import { Namespace } from ".";
|
|
3
|
+
export interface GettableProperties {
|
|
4
|
+
}
|
|
5
|
+
export interface TransformedProperties {
|
|
6
|
+
}
|
|
7
|
+
export interface SettableProperties {
|
|
8
|
+
}
|
|
9
|
+
export interface ObservableProperties {
|
|
10
|
+
}
|
|
11
|
+
export declare class Session extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
12
|
+
constructor(ableton: Ableton);
|
|
13
|
+
setupSessionBox(num_tracks: number, num_scenes: number): Promise<any>;
|
|
14
|
+
setSessionOffset(track_offset: number, scene_offset: number): Promise<any>;
|
|
15
|
+
}
|
package/ns/session.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Session = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
class Session extends _1.Namespace {
|
|
6
|
+
constructor(ableton) {
|
|
7
|
+
super(ableton, "session", undefined);
|
|
8
|
+
}
|
|
9
|
+
async setupSessionBox(num_tracks, num_scenes) {
|
|
10
|
+
return this.sendCommand("setup_session_box", { num_tracks, num_scenes });
|
|
11
|
+
}
|
|
12
|
+
async setSessionOffset(track_offset, scene_offset) {
|
|
13
|
+
return this.sendCommand("set_session_offset", {
|
|
14
|
+
track_offset,
|
|
15
|
+
scene_offset,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.Session = Session;
|
package/ns/track.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ export interface ObservableProperties {
|
|
|
131
131
|
input_meter_right: number;
|
|
132
132
|
is_frozen: number;
|
|
133
133
|
is_showing_chains: number;
|
|
134
|
-
mute:
|
|
134
|
+
mute: boolean;
|
|
135
135
|
muted_via_solo: number;
|
|
136
136
|
name: string;
|
|
137
137
|
output_meter_left: number;
|
|
@@ -141,14 +141,14 @@ export interface ObservableProperties {
|
|
|
141
141
|
solo: boolean;
|
|
142
142
|
}
|
|
143
143
|
export interface RawTrack {
|
|
144
|
-
id: string;
|
|
145
|
-
name: string;
|
|
146
|
-
color: number;
|
|
147
|
-
color_index: number;
|
|
148
|
-
is_foldable: boolean;
|
|
149
|
-
is_grouped: boolean;
|
|
150
|
-
mute: boolean;
|
|
151
|
-
solo: boolean;
|
|
144
|
+
readonly id: string;
|
|
145
|
+
readonly name: string;
|
|
146
|
+
readonly color: number;
|
|
147
|
+
readonly color_index: number;
|
|
148
|
+
readonly is_foldable: boolean;
|
|
149
|
+
readonly is_grouped: boolean;
|
|
150
|
+
readonly mute: boolean;
|
|
151
|
+
readonly solo: boolean;
|
|
152
152
|
}
|
|
153
153
|
export declare class Track extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
154
154
|
raw: RawTrack;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ableton-js",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Control Ableton Live from Node",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Leo Bernard <admin@leolabs.org>",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"build:doc": "jsdoc2md --files src/**/*.ts --configure ./jsdoc2md.json > ./API.md",
|
|
28
28
|
"version": "node hooks/prepublish.js && git add midi-script/version.py && auto-changelog -p -l 100 && git add CHANGELOG.md",
|
|
29
29
|
"build": "tsc",
|
|
30
|
-
"test": "vitest --run --no-threads"
|
|
30
|
+
"test": "vitest --run --no-threads",
|
|
31
|
+
"format": "prettier -w src/"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/lodash": "^4.14.194",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"@types/uuid": "^8.3.0",
|
|
38
39
|
"auto-changelog": "^2.3.0",
|
|
39
40
|
"p-all": "^3",
|
|
41
|
+
"prettier": "^3.3.3",
|
|
40
42
|
"tsx": "^3.12.7",
|
|
41
43
|
"typescript": "^5.1.3",
|
|
42
44
|
"vitest": "^0.32.4"
|