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 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
  ![Ableton Live Settings](https://i.imgur.com/a34zJca.png)
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 ableton:start` will copy the `midi-script` folder, open
35
- Ableton and show a stream of log messages until you kill it.
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: 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
- this.cache = new lru_cache_1.default({
71
- max: 500,
72
- ttl: 1000 * 60 * 10,
73
- ...options?.cacheOptions,
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
- this.client = dgram_1.default.createSocket({ type: "udp4" });
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 index = msg[0];
260
- const message = msg.slice(1);
261
- this.buffer[index] = message;
262
- // 0xFF signals that the end of the buffer has been reached
263
- if (index === 255) {
264
- this.handleUncompressedMessage((0, zlib_1.unzipSync)(Buffer.concat(this.buffer.filter((b) => b))).toString());
265
- this.buffer = [];
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.get(cacheKey);
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.set(cacheKey, result);
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() - 1;
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.slice(i * byteLimit, i * byteLimit + byteLimit),
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() {
@@ -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
@@ -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'\xFF' + compressed, self._client_addr)
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
- count_byte = struct.pack("B", i if i + 1 < count else 255)
164
- self._socket.sendto(count_byte + chunk, self._client_addr)
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
- buffer += data[1:]
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
- unzipped = zlib.decompress(buffer)
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):
@@ -1 +1 @@
1
- version = "3.4.6"
1
+ version = "3.6.0"
@@ -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;
@@ -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;
@@ -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: number;
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.4.6",
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"