ableton-js 3.7.2 → 4.0.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 +14 -0
- package/hooks/prepublish.js +13 -5
- package/index.d.ts +16 -15
- package/index.js +52 -58
- package/midi-script/AbletonJS.py +1 -1
- package/midi-script/Socket.py +20 -7
- package/midi-script/version.py +1 -1
- package/ns/application-view.d.ts +2 -2
- package/ns/application-view.js +4 -8
- package/ns/application.d.ts +4 -4
- package/ns/application.js +6 -10
- package/ns/browser-item.d.ts +2 -2
- package/ns/browser-item.js +2 -6
- package/ns/browser.d.ts +3 -3
- package/ns/browser.js +5 -9
- package/ns/clip-slot.d.ts +4 -4
- package/ns/clip-slot.js +8 -12
- package/ns/clip.d.ts +5 -5
- package/ns/clip.js +16 -20
- package/ns/cue-point.d.ts +2 -2
- package/ns/cue-point.js +2 -6
- package/ns/device-parameter.d.ts +2 -2
- package/ns/device-parameter.js +6 -10
- package/ns/device.d.ts +3 -3
- package/ns/device.js +6 -10
- package/ns/index.d.ts +1 -1
- package/ns/index.js +1 -5
- package/ns/internal.d.ts +2 -2
- package/ns/internal.js +5 -12
- package/ns/midi.d.ts +2 -2
- package/ns/midi.js +5 -10
- package/ns/mixer-device.d.ts +3 -3
- package/ns/mixer-device.js +16 -20
- package/ns/scene.d.ts +4 -4
- package/ns/scene.js +6 -10
- package/ns/session.d.ts +2 -2
- package/ns/session.js +2 -6
- package/ns/song-view.d.ts +8 -8
- package/ns/song-view.js +12 -16
- package/ns/song.d.ts +7 -7
- package/ns/song.js +23 -27
- package/ns/track-view.d.ts +3 -3
- package/ns/track-view.js +6 -10
- package/ns/track.d.ts +8 -8
- package/ns/track.js +19 -23
- package/package.json +12 -4
- package/util/cache.js +1 -5
- package/util/color.js +1 -5
- package/util/logger.js +1 -2
- package/util/note.js +2 -7
- package/util/package-version.d.ts +1 -1
- package/util/package-version.js +1 -20
- package/util/tests.d.ts +1 -1
- package/util/tests.js +3 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,22 @@ 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
|
+
#### [v4.0.0](https://github.com/leolabs/ableton.js/compare/v3.7.3...v4.0.0)
|
|
8
|
+
|
|
9
|
+
- :bug: Fix Vitest not working with new ESM import syntax [`405bd76`](https://github.com/leolabs/ableton.js/commit/405bd76df064e3f085824b3e48098adbde6f1b88)
|
|
10
|
+
- :truck: Switch the library to ESM [`cf382ff`](https://github.com/leolabs/ableton.js/commit/cf382ff905fcde275ae805e0ca93f55d29aa7679)
|
|
11
|
+
- :sparkles: Add proper rate limiting to avoid missed packets [`70a571c`](https://github.com/leolabs/ableton.js/commit/70a571c562691baeaa1f661103ad81d93b7d3a22)
|
|
12
|
+
|
|
13
|
+
#### [v3.7.3](https://github.com/leolabs/ableton.js/compare/v3.7.2...v3.7.3)
|
|
14
|
+
|
|
15
|
+
> 8 December 2025
|
|
16
|
+
|
|
17
|
+
- :bug: Fix Live not properly sending "disconnect" events [`21fd462`](https://github.com/leolabs/ableton.js/commit/21fd46247fb62f753a5bab5f0549fb8a4998dbfc)
|
|
18
|
+
|
|
7
19
|
#### [v3.7.2](https://github.com/leolabs/ableton.js/compare/v3.7.1...v3.7.2)
|
|
8
20
|
|
|
21
|
+
> 2 December 2025
|
|
22
|
+
|
|
9
23
|
- Fix a missing str() coercion [`#136`](https://github.com/leolabs/ableton.js/pull/136)
|
|
10
24
|
- :bug: Fix issues with larger payloads not being received properly [`bed4e22`](https://github.com/leolabs/ableton.js/commit/bed4e226cb7febb448700c32979ce50a6a67ef69)
|
|
11
25
|
- :zap: Always assign a new port to the Python UDP server on start and store it in the port file [`47566f9`](https://github.com/leolabs/ableton.js/commit/47566f9eb347784746f6d50093491f3b2d591c58)
|
package/hooks/prepublish.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
5
|
+
|
|
6
|
+
const rootPath = path.join(import.meta.dirname, "..");
|
|
7
|
+
|
|
8
|
+
const internalPath = path.join(rootPath, "midi-script", "version.py");
|
|
4
9
|
|
|
5
|
-
const internalPath = path.join(__dirname, "..", "midi-script", "version.py");
|
|
6
10
|
const file = fs.readFileSync(internalPath);
|
|
7
11
|
|
|
8
12
|
const replaced = file
|
|
9
13
|
.toString()
|
|
10
|
-
.replace(/version = "(.+\..+\..+?)"$/m, `version = "${
|
|
14
|
+
.replace(/version = "(.+\..+\..+?)"$/m, `version = "${packageJson.version}"`);
|
|
11
15
|
|
|
12
16
|
fs.writeFileSync(internalPath, replaced);
|
|
17
|
+
fs.writeFileSync(
|
|
18
|
+
path.join(rootPath, "util", "package-version.js"),
|
|
19
|
+
`export const packageVersion = "${packageJson.version}";`,
|
|
20
|
+
);
|
package/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
2
|
import LruCache from "lru-cache";
|
|
3
|
-
import { Song } from "./ns/song";
|
|
4
|
-
import { Internal } from "./ns/internal";
|
|
5
|
-
import { Application } from "./ns/application";
|
|
6
|
-
import { Midi } from "./ns/midi";
|
|
7
|
-
import { Cache } from "./util/cache";
|
|
8
|
-
import { Logger } from "./util/logger";
|
|
9
|
-
import { Session } from "./ns/session";
|
|
3
|
+
import { Song } from "./ns/song.js";
|
|
4
|
+
import { Internal } from "./ns/internal.js";
|
|
5
|
+
import { Application } from "./ns/application.js";
|
|
6
|
+
import { Midi } from "./ns/midi.js";
|
|
7
|
+
import { Cache } from "./util/cache.js";
|
|
8
|
+
import { Logger } from "./util/logger.js";
|
|
9
|
+
import { Session } from "./ns/session.js";
|
|
10
10
|
interface Command {
|
|
11
11
|
uuid: string;
|
|
12
12
|
ns: string;
|
|
@@ -20,12 +20,13 @@ interface Command {
|
|
|
20
20
|
}
|
|
21
21
|
type DisconnectEventType = "realtime" | "heartbeat";
|
|
22
22
|
type ConnectEventType = DisconnectEventType | "start";
|
|
23
|
-
interface
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
interface EventMap {
|
|
24
|
+
connect: [ConnectEventType];
|
|
25
|
+
disconnect: [DisconnectEventType];
|
|
26
|
+
raw_message: [string];
|
|
27
|
+
message: [any];
|
|
28
|
+
error: [Error];
|
|
29
|
+
ping: [number];
|
|
29
30
|
}
|
|
30
31
|
export interface EventListener {
|
|
31
32
|
prop: string;
|
|
@@ -92,7 +93,7 @@ export interface AbletonOptions {
|
|
|
92
93
|
*/
|
|
93
94
|
logger?: Logger;
|
|
94
95
|
}
|
|
95
|
-
export declare class Ableton extends EventEmitter
|
|
96
|
+
export declare class Ableton extends EventEmitter<EventMap> {
|
|
96
97
|
private options?;
|
|
97
98
|
private client;
|
|
98
99
|
private msgMap;
|
|
@@ -160,4 +161,4 @@ export declare class Ableton extends EventEmitter implements ConnectionEventEmit
|
|
|
160
161
|
sendRaw(msg: string, messageId: number): Promise<void>;
|
|
161
162
|
isConnected(): boolean;
|
|
162
163
|
}
|
|
163
|
-
export {
|
|
164
|
+
export { packageVersion } from "./util/package-version.js";
|
package/index.js
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const application_1 = require("./ns/application");
|
|
21
|
-
const midi_1 = require("./ns/midi");
|
|
22
|
-
const package_version_1 = require("./util/package-version");
|
|
23
|
-
const cache_1 = require("./util/cache");
|
|
24
|
-
const session_1 = require("./ns/session");
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import dgram from "node:dgram";
|
|
4
|
+
import { truncate } from "lodash";
|
|
5
|
+
import { EventEmitter } from "events";
|
|
6
|
+
import { v4 } from "uuid";
|
|
7
|
+
import semver from "semver";
|
|
8
|
+
import { unzipSync, deflateSync } from "zlib";
|
|
9
|
+
import LruCache from "lru-cache";
|
|
10
|
+
import { unwatchFile, watchFile } from "node:fs";
|
|
11
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
12
|
+
import pLimit from "p-limit";
|
|
13
|
+
import { Song } from "./ns/song.js";
|
|
14
|
+
import { Internal } from "./ns/internal.js";
|
|
15
|
+
import { Application } from "./ns/application.js";
|
|
16
|
+
import { Midi } from "./ns/midi.js";
|
|
17
|
+
import { packageVersion } from "./util/package-version.js";
|
|
18
|
+
import { isCached } from "./util/cache.js";
|
|
19
|
+
import { Session } from "./ns/session.js";
|
|
25
20
|
const SERVER_PORT_FILE = "ableton-js-server.port";
|
|
26
21
|
const CLIENT_PORT_FILE = "ableton-js-client.port";
|
|
27
|
-
|
|
22
|
+
const limit = pLimit(200);
|
|
23
|
+
export class TimeoutError extends Error {
|
|
28
24
|
message;
|
|
29
25
|
payload;
|
|
30
26
|
constructor(message, payload) {
|
|
@@ -33,8 +29,7 @@ class TimeoutError extends Error {
|
|
|
33
29
|
this.payload = payload;
|
|
34
30
|
}
|
|
35
31
|
}
|
|
36
|
-
|
|
37
|
-
class DisconnectError extends Error {
|
|
32
|
+
export class DisconnectError extends Error {
|
|
38
33
|
message;
|
|
39
34
|
payload;
|
|
40
35
|
constructor(message, payload) {
|
|
@@ -43,8 +38,7 @@ class DisconnectError extends Error {
|
|
|
43
38
|
this.payload = payload;
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
|
-
|
|
47
|
-
class Ableton extends events_1.EventEmitter {
|
|
41
|
+
export class Ableton extends EventEmitter {
|
|
48
42
|
options;
|
|
49
43
|
client;
|
|
50
44
|
msgMap = new Map();
|
|
@@ -57,11 +51,11 @@ class Ableton extends events_1.EventEmitter {
|
|
|
57
51
|
messageId = 0;
|
|
58
52
|
serverPort;
|
|
59
53
|
cache;
|
|
60
|
-
song = new
|
|
61
|
-
session = new
|
|
62
|
-
application = new
|
|
63
|
-
internal = new
|
|
64
|
-
midi = new
|
|
54
|
+
song = new Song(this);
|
|
55
|
+
session = new Session(this); // added for red session ring control
|
|
56
|
+
application = new Application(this);
|
|
57
|
+
internal = new Internal(this);
|
|
58
|
+
midi = new Midi(this);
|
|
65
59
|
clientPortFile;
|
|
66
60
|
serverPortFile;
|
|
67
61
|
logger;
|
|
@@ -72,14 +66,14 @@ class Ableton extends events_1.EventEmitter {
|
|
|
72
66
|
this.options = options;
|
|
73
67
|
this.logger = options?.logger;
|
|
74
68
|
if (!options?.disableCache) {
|
|
75
|
-
this.cache = new
|
|
69
|
+
this.cache = new LruCache({
|
|
76
70
|
max: 500,
|
|
77
71
|
ttl: 1000 * 60 * 10,
|
|
78
72
|
...options?.cacheOptions,
|
|
79
73
|
});
|
|
80
74
|
}
|
|
81
|
-
this.clientPortFile =
|
|
82
|
-
this.serverPortFile =
|
|
75
|
+
this.clientPortFile = path.join(os.tmpdir(), this.options?.clientPortFile ?? CLIENT_PORT_FILE);
|
|
76
|
+
this.serverPortFile = path.join(os.tmpdir(), this.options?.serverPortFile ?? SERVER_PORT_FILE);
|
|
83
77
|
}
|
|
84
78
|
handleConnect(type) {
|
|
85
79
|
if (!this._isConnected) {
|
|
@@ -132,19 +126,19 @@ class Ableton extends events_1.EventEmitter {
|
|
|
132
126
|
this.clientState = "starting";
|
|
133
127
|
// The recvBufferSize is set to macOS' default value, so the
|
|
134
128
|
// socket behaves the same on Windows and doesn't drop any packets
|
|
135
|
-
this.client =
|
|
129
|
+
this.client = dgram.createSocket({ type: "udp4", recvBufferSize: 786896 });
|
|
136
130
|
this.client.addListener("message", this.handleIncoming.bind(this));
|
|
137
131
|
this.client.addListener("listening", async () => {
|
|
138
132
|
const port = this.client?.address().port;
|
|
139
133
|
this.logger?.info("Client is bound and listening", { port });
|
|
140
134
|
// Write used port to a file so Live can read from it on startup
|
|
141
|
-
await
|
|
135
|
+
await writeFile(this.clientPortFile, String(port));
|
|
142
136
|
});
|
|
143
137
|
this.client.bind(undefined, "127.0.0.1");
|
|
144
138
|
// Wait for the server port file to exist
|
|
145
139
|
const sentPort = await new Promise(async (res) => {
|
|
146
140
|
try {
|
|
147
|
-
const serverPort = await
|
|
141
|
+
const serverPort = await readFile(this.serverPortFile);
|
|
148
142
|
this.serverPort = Number(serverPort.toString());
|
|
149
143
|
this.logger?.info("Server port:", { port: this.serverPort });
|
|
150
144
|
res(false);
|
|
@@ -153,9 +147,9 @@ class Ableton extends events_1.EventEmitter {
|
|
|
153
147
|
this.logger?.info("Server doesn't seem to be online yet, waiting for it to go online...");
|
|
154
148
|
}
|
|
155
149
|
// Set up a watcher in case the server port changes
|
|
156
|
-
|
|
150
|
+
watchFile(this.serverPortFile, async (curr) => {
|
|
157
151
|
if (curr.isFile()) {
|
|
158
|
-
const serverPort = await
|
|
152
|
+
const serverPort = await readFile(this.serverPortFile);
|
|
159
153
|
const newPort = Number(serverPort.toString());
|
|
160
154
|
if (!isNaN(newPort) && newPort !== this.serverPort) {
|
|
161
155
|
this.logger?.info("Server port changed:", { port: newPort });
|
|
@@ -228,8 +222,8 @@ class Ableton extends events_1.EventEmitter {
|
|
|
228
222
|
this.internal
|
|
229
223
|
.get("version")
|
|
230
224
|
.then((v) => {
|
|
231
|
-
const jsVersion =
|
|
232
|
-
if (
|
|
225
|
+
const jsVersion = packageVersion;
|
|
226
|
+
if (semver.lt(v, jsVersion)) {
|
|
233
227
|
this.logger?.warn(`The installed version of your AbletonJS plugin (${v}) is lower than the JS library (${jsVersion}).`, "Please update your AbletonJS plugin to the latest version: https://git.io/JvaOu");
|
|
234
228
|
}
|
|
235
229
|
})
|
|
@@ -238,7 +232,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
238
232
|
/** Closes the client */
|
|
239
233
|
async close() {
|
|
240
234
|
this.logger?.info("Closing the client");
|
|
241
|
-
|
|
235
|
+
unwatchFile(this.serverPortFile);
|
|
242
236
|
if (this.heartbeatInterval) {
|
|
243
237
|
clearInterval(this.heartbeatInterval);
|
|
244
238
|
}
|
|
@@ -271,7 +265,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
271
265
|
// Reset the timeout when receiving a new message
|
|
272
266
|
this.timeoutMap.get(messageId)?.();
|
|
273
267
|
if (messageIndex === 0 && totalMessages === 1) {
|
|
274
|
-
this.handleUncompressedMessage(
|
|
268
|
+
this.handleUncompressedMessage(unzipSync(message).toString());
|
|
275
269
|
return;
|
|
276
270
|
}
|
|
277
271
|
if (!this.buffer[messageId]) {
|
|
@@ -279,7 +273,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
279
273
|
}
|
|
280
274
|
this.buffer[messageId][messageIndex] = message;
|
|
281
275
|
if (this.buffer[messageId].filter(Boolean).length === totalMessages) {
|
|
282
|
-
this.handleUncompressedMessage(
|
|
276
|
+
this.handleUncompressedMessage(unzipSync(Buffer.concat(this.buffer[messageId])).toString());
|
|
283
277
|
delete this.buffer[messageId];
|
|
284
278
|
}
|
|
285
279
|
}
|
|
@@ -331,16 +325,18 @@ class Ableton extends events_1.EventEmitter {
|
|
|
331
325
|
* A good starting point in general is the `song` prop.
|
|
332
326
|
*/
|
|
333
327
|
async sendCommand(command) {
|
|
334
|
-
return new Promise((res, rej) => {
|
|
335
|
-
const msgId =
|
|
328
|
+
return limit(() => new Promise((res, rej) => {
|
|
329
|
+
const msgId = v4();
|
|
336
330
|
const payload = {
|
|
337
331
|
uuid: msgId,
|
|
338
332
|
...command,
|
|
339
333
|
};
|
|
340
334
|
const msg = JSON.stringify(payload);
|
|
341
335
|
const timeout = this.options?.commandTimeoutMs ?? 2000;
|
|
342
|
-
const arg =
|
|
343
|
-
const cls = command.nsid
|
|
336
|
+
const arg = truncate(JSON.stringify(command.args), { length: 100 });
|
|
337
|
+
const cls = command.nsid
|
|
338
|
+
? `${command.ns}(${command.nsid})`
|
|
339
|
+
: command.ns;
|
|
344
340
|
this.messageId = (this.messageId + 1) % 256;
|
|
345
341
|
let timeoutId = null;
|
|
346
342
|
const clearCurrentTimeout = () => {
|
|
@@ -376,7 +372,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
376
372
|
},
|
|
377
373
|
});
|
|
378
374
|
this.sendRaw(msg, this.messageId).finally(startTimeout);
|
|
379
|
-
});
|
|
375
|
+
}));
|
|
380
376
|
}
|
|
381
377
|
async sendCachedCommand(command) {
|
|
382
378
|
const args = command.args?.prop ?? JSON.stringify(command.args);
|
|
@@ -387,7 +383,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
387
383
|
etag: cached?.etag,
|
|
388
384
|
cache: true,
|
|
389
385
|
});
|
|
390
|
-
if (
|
|
386
|
+
if (isCached(result)) {
|
|
391
387
|
if (!cached) {
|
|
392
388
|
throw new Error("Tried to get an object that isn't cached.");
|
|
393
389
|
}
|
|
@@ -420,7 +416,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
420
416
|
});
|
|
421
417
|
}
|
|
422
418
|
async addPropListener(ns, nsid, prop, listener) {
|
|
423
|
-
const eventId =
|
|
419
|
+
const eventId = v4();
|
|
424
420
|
const result = await this.sendCommand({
|
|
425
421
|
ns,
|
|
426
422
|
nsid,
|
|
@@ -470,7 +466,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
470
466
|
if (!this.client || !this.serverPort) {
|
|
471
467
|
throw new Error("The client hasn't been started yet. Please call start() first.");
|
|
472
468
|
}
|
|
473
|
-
const buffer =
|
|
469
|
+
const buffer = deflateSync(Buffer.from(msg));
|
|
474
470
|
const byteLimit = this.client.getSendBufferSize() - 100;
|
|
475
471
|
const totalChunks = Math.ceil(buffer.byteLength / byteLimit);
|
|
476
472
|
// Split the message into chunks if it becomes too large
|
|
@@ -495,6 +491,4 @@ class Ableton extends events_1.EventEmitter {
|
|
|
495
491
|
return this._isConnected;
|
|
496
492
|
}
|
|
497
493
|
}
|
|
498
|
-
|
|
499
|
-
var package_version_2 = require("./util/package-version");
|
|
500
|
-
Object.defineProperty(exports, "getPackageVersion", { enumerable: true, get: function () { return package_version_2.getPackageVersion; } });
|
|
494
|
+
export { packageVersion } from "./util/package-version.js";
|
package/midi-script/AbletonJS.py
CHANGED
|
@@ -106,7 +106,7 @@ class AbletonJS(ControlSurface):
|
|
|
106
106
|
logger.info("Disconnecting")
|
|
107
107
|
if FAST_POLLING:
|
|
108
108
|
self.recv_loop.stop()
|
|
109
|
-
self.socket.send("disconnect")
|
|
109
|
+
self.socket.send("disconnect", immediate=True)
|
|
110
110
|
self.socket.shutdown()
|
|
111
111
|
Interface.listeners.clear()
|
|
112
112
|
super(AbletonJS, self).disconnect()
|
package/midi-script/Socket.py
CHANGED
|
@@ -77,13 +77,22 @@ class Socket(object):
|
|
|
77
77
|
self._client_addr = ("127.0.0.1", port)
|
|
78
78
|
|
|
79
79
|
if self._socket:
|
|
80
|
-
self.send(
|
|
80
|
+
self.send(
|
|
81
|
+
"connect", {"port": self._server_addr[1]}, immediate=True)
|
|
81
82
|
except Exception as e:
|
|
82
83
|
self.log_error_once(
|
|
83
84
|
"Couldn't read remote port file: " + str(e.args))
|
|
84
85
|
|
|
85
86
|
def shutdown(self):
|
|
86
87
|
logger.info("Shutting down...")
|
|
88
|
+
send_buffer_length = len(self._send_buffer)
|
|
89
|
+
|
|
90
|
+
for i, packet in enumerate(self._send_buffer):
|
|
91
|
+
logger.info("Sending remaining packet " + str(i) +
|
|
92
|
+
" of " + str(send_buffer_length))
|
|
93
|
+
self._socket.sendto(packet, self._client_addr)
|
|
94
|
+
|
|
95
|
+
self._send_buffer.clear()
|
|
87
96
|
self._socket.close()
|
|
88
97
|
self._socket = None
|
|
89
98
|
|
|
@@ -115,7 +124,7 @@ class Socket(object):
|
|
|
115
124
|
raise e
|
|
116
125
|
|
|
117
126
|
try:
|
|
118
|
-
self.send("connect", {"port": port})
|
|
127
|
+
self.send("connect", {"port": port}, immediate=True)
|
|
119
128
|
except Exception as e:
|
|
120
129
|
logger.error("Couldn't send connect to " +
|
|
121
130
|
str(self._client_addr) + ":")
|
|
@@ -137,7 +146,7 @@ class Socket(object):
|
|
|
137
146
|
callback=self.init_socket, interval=5000, repeat=False)
|
|
138
147
|
t.start()
|
|
139
148
|
|
|
140
|
-
def _sendto(self, msg):
|
|
149
|
+
def _sendto(self, msg, immediate):
|
|
141
150
|
'''Send a raw message to the client, compressed and chunked, if necessary'''
|
|
142
151
|
compressed = zlib.compress(msg.encode("utf8")) + b'\n'
|
|
143
152
|
|
|
@@ -148,8 +157,12 @@ class Socket(object):
|
|
|
148
157
|
message_id_byte = struct.pack("B", self._message_id)
|
|
149
158
|
|
|
150
159
|
if len(compressed) < self._chunk_limit:
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
packet = message_id_byte + b'\x00\x01' + compressed
|
|
161
|
+
|
|
162
|
+
if immediate:
|
|
163
|
+
self._socket.sendto(packet, self._client_addr)
|
|
164
|
+
else:
|
|
165
|
+
self._send_buffer.append(packet)
|
|
153
166
|
else:
|
|
154
167
|
chunks = list(split_by_n(compressed, self._chunk_limit))
|
|
155
168
|
count = len(chunks)
|
|
@@ -159,7 +172,7 @@ class Socket(object):
|
|
|
159
172
|
self._send_buffer.append(
|
|
160
173
|
message_id_byte + packet_byte + count_byte + chunk)
|
|
161
174
|
|
|
162
|
-
def send(self, name, obj=None, uuid=None):
|
|
175
|
+
def send(self, name, obj=None, uuid=None, immediate=False):
|
|
163
176
|
def jsonReplace(o):
|
|
164
177
|
try:
|
|
165
178
|
return list(o)
|
|
@@ -173,7 +186,7 @@ class Socket(object):
|
|
|
173
186
|
try:
|
|
174
187
|
data = json.dumps(
|
|
175
188
|
{"event": name, "data": obj, "uuid": uuid}, default=jsonReplace, ensure_ascii=False)
|
|
176
|
-
self._sendto(data)
|
|
189
|
+
self._sendto(data, immediate)
|
|
177
190
|
except socket.error as e:
|
|
178
191
|
logger.error("Socket error:")
|
|
179
192
|
logger.exception(e)
|
package/midi-script/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "
|
|
1
|
+
version = "4.0.0"
|
package/ns/application-view.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Ableton } from "
|
|
2
|
-
import { Namespace } from ".";
|
|
1
|
+
import { Ableton } from "../index.js";
|
|
2
|
+
import { Namespace } from "./index.js";
|
|
3
3
|
export type DocumentView = "Session" | "Arranger";
|
|
4
4
|
export type DetailView = "Detail" | "Detail/Clip" | "Detail/DeviceChain";
|
|
5
5
|
export type View = "Browser" | DocumentView | DetailView;
|
package/ns/application-view.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.ApplicationView = exports.NavDirection = void 0;
|
|
4
|
-
const _1 = require(".");
|
|
5
|
-
var NavDirection;
|
|
1
|
+
import { Namespace } from "./index.js";
|
|
2
|
+
export var NavDirection;
|
|
6
3
|
(function (NavDirection) {
|
|
7
4
|
NavDirection[NavDirection["Up"] = 0] = "Up";
|
|
8
5
|
NavDirection[NavDirection["Down"] = 1] = "Down";
|
|
9
6
|
NavDirection[NavDirection["Left"] = 2] = "Left";
|
|
10
7
|
NavDirection[NavDirection["Right"] = 3] = "Right";
|
|
11
|
-
})(NavDirection || (
|
|
12
|
-
class ApplicationView extends
|
|
8
|
+
})(NavDirection || (NavDirection = {}));
|
|
9
|
+
export class ApplicationView extends Namespace {
|
|
13
10
|
constructor(ableton) {
|
|
14
11
|
super(ableton, "application-view");
|
|
15
12
|
}
|
|
@@ -38,4 +35,3 @@ class ApplicationView extends _1.Namespace {
|
|
|
38
35
|
return this.sendCommand("zoom_view", [direction, view, true]);
|
|
39
36
|
}
|
|
40
37
|
}
|
|
41
|
-
exports.ApplicationView = ApplicationView;
|
package/ns/application.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Ableton } from "
|
|
2
|
-
import { Namespace } from ".";
|
|
3
|
-
import { ApplicationView } from "./application-view";
|
|
4
|
-
import { Browser, RawBrowser } from "./browser";
|
|
1
|
+
import { Ableton } from "../index.js";
|
|
2
|
+
import { Namespace } from "./index.js";
|
|
3
|
+
import { ApplicationView } from "./application-view.js";
|
|
4
|
+
import { Browser, RawBrowser } from "./browser.js";
|
|
5
5
|
export interface GettableProperties {
|
|
6
6
|
bugfix_version: number;
|
|
7
7
|
major_version: number;
|
package/ns/application.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const application_view_1 = require("./application-view");
|
|
6
|
-
const browser_1 = require("./browser");
|
|
7
|
-
class Application extends _1.Namespace {
|
|
1
|
+
import { Namespace } from "./index.js";
|
|
2
|
+
import { ApplicationView } from "./application-view.js";
|
|
3
|
+
import { Browser } from "./browser.js";
|
|
4
|
+
export class Application extends Namespace {
|
|
8
5
|
constructor(ableton) {
|
|
9
6
|
super(ableton, "application");
|
|
10
7
|
}
|
|
11
|
-
browser = new
|
|
12
|
-
view = new
|
|
8
|
+
browser = new Browser(this.ableton);
|
|
9
|
+
view = new ApplicationView(this.ableton);
|
|
13
10
|
async pressCurrentDialogButton(index) {
|
|
14
11
|
return this.sendCommand("press_current_dialog_button", [index]);
|
|
15
12
|
}
|
|
16
13
|
}
|
|
17
|
-
exports.Application = Application;
|
package/ns/browser-item.d.ts
CHANGED
package/ns/browser-item.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.BrowserItem = void 0;
|
|
4
|
-
const _1 = require(".");
|
|
5
|
-
class BrowserItem extends _1.Namespace {
|
|
1
|
+
import { Namespace } from "./index.js";
|
|
2
|
+
export class BrowserItem extends Namespace {
|
|
6
3
|
raw;
|
|
7
4
|
constructor(ableton, raw) {
|
|
8
5
|
super(ableton, "browser-item", raw.id);
|
|
@@ -22,4 +19,3 @@ class BrowserItem extends _1.Namespace {
|
|
|
22
19
|
};
|
|
23
20
|
}
|
|
24
21
|
}
|
|
25
|
-
exports.BrowserItem = BrowserItem;
|
package/ns/browser.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Ableton } from "
|
|
2
|
-
import { Namespace } from ".";
|
|
3
|
-
import { BrowserItem, RawBrowserItem } from "./browser-item";
|
|
1
|
+
import { Ableton } from "../index.js";
|
|
2
|
+
import { Namespace } from "./index.js";
|
|
3
|
+
import { BrowserItem, RawBrowserItem } from "./browser-item.js";
|
|
4
4
|
export interface GettableProperties {
|
|
5
5
|
audio_effects: RawBrowserItem[];
|
|
6
6
|
clips: RawBrowserItem[];
|
package/ns/browser.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const _1 = require(".");
|
|
5
|
-
const browser_item_1 = require("./browser-item");
|
|
6
|
-
class Browser extends _1.Namespace {
|
|
1
|
+
import { Namespace } from "./index.js";
|
|
2
|
+
import { BrowserItem } from "./browser-item.js";
|
|
3
|
+
export class Browser extends Namespace {
|
|
7
4
|
constructor(ableton) {
|
|
8
5
|
super(ableton, "browser");
|
|
9
|
-
const makeBrowserItems = (items) => items.map((item) => new
|
|
6
|
+
const makeBrowserItems = (items) => items.map((item) => new BrowserItem(ableton, item));
|
|
10
7
|
this.transformers = {
|
|
11
8
|
audio_effects: makeBrowserItems,
|
|
12
9
|
clips: makeBrowserItems,
|
|
@@ -22,7 +19,7 @@ class Browser extends _1.Namespace {
|
|
|
22
19
|
sounds: makeBrowserItems,
|
|
23
20
|
user_library: makeBrowserItems,
|
|
24
21
|
user_folders: makeBrowserItems,
|
|
25
|
-
hotswap_target: (t) => new
|
|
22
|
+
hotswap_target: (t) => new BrowserItem(ableton, t),
|
|
26
23
|
};
|
|
27
24
|
this.cachedProps = {
|
|
28
25
|
audio_effects: true,
|
|
@@ -55,4 +52,3 @@ class Browser extends _1.Namespace {
|
|
|
55
52
|
return this.sendCommand("stop_preview");
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
|
-
exports.Browser = Browser;
|
package/ns/clip-slot.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Ableton } from "
|
|
2
|
-
import { Namespace } from ".";
|
|
3
|
-
import { Color } from "../util/color";
|
|
4
|
-
import { Clip, RawClip } from "./clip";
|
|
1
|
+
import { Ableton } from "../index.js";
|
|
2
|
+
import { Namespace } from "./index.js";
|
|
3
|
+
import { Color } from "../util/color.js";
|
|
4
|
+
import { Clip, RawClip } from "./clip.js";
|
|
5
5
|
export declare enum PlayingStatus {
|
|
6
6
|
Stopped = "stopped",
|
|
7
7
|
Playing = "playing",
|
package/ns/clip-slot.js
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const color_1 = require("../util/color");
|
|
6
|
-
const clip_1 = require("./clip");
|
|
7
|
-
var PlayingStatus;
|
|
1
|
+
import { Namespace } from "./index.js";
|
|
2
|
+
import { Color } from "../util/color.js";
|
|
3
|
+
import { Clip } from "./clip.js";
|
|
4
|
+
export var PlayingStatus;
|
|
8
5
|
(function (PlayingStatus) {
|
|
9
6
|
PlayingStatus["Stopped"] = "stopped";
|
|
10
7
|
PlayingStatus["Playing"] = "playing";
|
|
11
8
|
PlayingStatus["Recording"] = "recording";
|
|
12
|
-
})(PlayingStatus || (
|
|
9
|
+
})(PlayingStatus || (PlayingStatus = {}));
|
|
13
10
|
/**
|
|
14
11
|
* This class represents an entry in Live's Session view matrix.
|
|
15
12
|
*/
|
|
16
|
-
class ClipSlot extends
|
|
13
|
+
export class ClipSlot extends Namespace {
|
|
17
14
|
raw;
|
|
18
15
|
constructor(ableton, raw) {
|
|
19
16
|
super(ableton, "clip_slot", raw.id);
|
|
20
17
|
this.raw = raw;
|
|
21
18
|
this.transformers = {
|
|
22
|
-
clip: (c) => (c ? new
|
|
23
|
-
color: (c) => new
|
|
19
|
+
clip: (c) => (c ? new Clip(ableton, c) : null),
|
|
20
|
+
color: (c) => new Color(c),
|
|
24
21
|
};
|
|
25
22
|
this.cachedProps = {
|
|
26
23
|
clip: true,
|
|
@@ -65,4 +62,3 @@ class ClipSlot extends _1.Namespace {
|
|
|
65
62
|
return this.sendCommand("stop");
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
|
-
exports.ClipSlot = ClipSlot;
|
package/ns/clip.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Ableton } from "
|
|
2
|
-
import { Namespace } from ".";
|
|
3
|
-
import { Color } from "../util/color";
|
|
4
|
-
import { DeviceParameter } from "./device-parameter";
|
|
5
|
-
import { Note, NoteExtended, NoteTuple } from "../util/note";
|
|
1
|
+
import { Ableton } from "../index.js";
|
|
2
|
+
import { Namespace } from "./index.js";
|
|
3
|
+
import { Color } from "../util/color.js";
|
|
4
|
+
import { DeviceParameter } from "./device-parameter.js";
|
|
5
|
+
import { Note, NoteExtended, NoteTuple } from "../util/note.js";
|
|
6
6
|
export declare enum WarpMode {
|
|
7
7
|
Beats = 0,
|
|
8
8
|
Tones = 1,
|