ableton-js 3.1.1 → 3.1.3
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 +16 -0
- package/index.d.ts +1 -0
- package/index.js +18 -9
- package/midi-script/Interface.py +2 -1
- package/midi-script/Internal.py +1 -1
- package/midi-script/Socket.py +77 -33
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,24 @@ 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.1.3](https://github.com/leolabs/ableton.js/compare/v3.1.2...v3.1.3)
|
|
8
|
+
|
|
9
|
+
- :bug: Fix opening a project file from within Finder closing all socket and file handles [`6cf2440`](https://github.com/leolabs/ableton.js/commit/6cf244057797dd45a7f5007af907947754449d5d)
|
|
10
|
+
- :loud_sound: Log data that couldn't be sent [`e39c6c6`](https://github.com/leolabs/ableton.js/commit/e39c6c6b0b68823268ca715c486dbc1ab6ce7dec)
|
|
11
|
+
- :loud_sound: Improve logging for event handlers [`a1fa33b`](https://github.com/leolabs/ableton.js/commit/a1fa33bb9c1c6b05352ea845c24b4637c7f80094)
|
|
12
|
+
|
|
13
|
+
#### [v3.1.2](https://github.com/leolabs/ableton.js/compare/v3.1.1...v3.1.2)
|
|
14
|
+
|
|
15
|
+
> 26 February 2023
|
|
16
|
+
|
|
17
|
+
- :sparkles: Keep a handle to the client port file open for faster read performance [`2a0295d`](https://github.com/leolabs/ableton.js/commit/2a0295dff3022e3812c2a0f6077ffb7bdcd00bf0)
|
|
18
|
+
- :sparkles: Try re-using the previous port for a quicker reconnect [`5c77760`](https://github.com/leolabs/ableton.js/commit/5c777606ce97295429dcac1a5685a34c8aa5abe3)
|
|
19
|
+
- :bug: Fix double disconnect/connect event [`2f960be`](https://github.com/leolabs/ableton.js/commit/2f960be4c6d18b2668d15258914cd3b763be0f4a)
|
|
20
|
+
|
|
7
21
|
#### [v3.1.1](https://github.com/leolabs/ableton.js/compare/v3.1.0...v3.1.1)
|
|
8
22
|
|
|
23
|
+
> 25 February 2023
|
|
24
|
+
|
|
9
25
|
- :loud_sound: Log connect and disconnect events [`e69f610`](https://github.com/leolabs/ableton.js/commit/e69f61098d61fd4027db4e94aad8155db5dbb504)
|
|
10
26
|
- :bug: Don't count a failed ping as a successful connection event [`217e91e`](https://github.com/leolabs/ableton.js/commit/217e91ed936326c29a391ace9dcbe831125f4fa2)
|
|
11
27
|
|
package/index.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ export declare class Ableton extends EventEmitter implements ConnectionEventEmit
|
|
|
63
63
|
private serverPortFile;
|
|
64
64
|
private logger;
|
|
65
65
|
private clientState;
|
|
66
|
+
private cancelDisconnectEvent;
|
|
66
67
|
constructor(options?: AbletonOptions | undefined);
|
|
67
68
|
private handleConnect;
|
|
68
69
|
private handleDisconnect;
|
package/index.js
CHANGED
|
@@ -132,6 +132,7 @@ var Ableton = /** @class */ (function (_super) {
|
|
|
132
132
|
_this.internal = new internal_1.Internal(_this);
|
|
133
133
|
_this.midi = new midi_1.Midi(_this);
|
|
134
134
|
_this.clientState = "closed";
|
|
135
|
+
_this.cancelDisconnectEvent = false;
|
|
135
136
|
_this.logger = options === null || options === void 0 ? void 0 : options.logger;
|
|
136
137
|
_this.cache = new lru_cache_1.default(__assign({ max: 500, ttl: 1000 * 60 * 10 }, options === null || options === void 0 ? void 0 : options.cacheOptions));
|
|
137
138
|
_this.clientPortFile = path_1.default.join(os_1.default.tmpdir(), (_b = (_a = _this.options) === null || _a === void 0 ? void 0 : _a.clientPortFile) !== null && _b !== void 0 ? _b : CLIENT_PORT_FILE);
|
|
@@ -290,17 +291,22 @@ var Ableton = /** @class */ (function (_super) {
|
|
|
290
291
|
return __generator(this, function (_a) {
|
|
291
292
|
switch (_a.label) {
|
|
292
293
|
case 0:
|
|
293
|
-
_a.trys.push([0, 2, ,
|
|
294
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
294
295
|
return [4 /*yield*/, this.internal.get("ping")];
|
|
295
296
|
case 1:
|
|
296
297
|
_a.sent();
|
|
297
298
|
this.handleConnect("heartbeat");
|
|
298
|
-
return [3 /*break*/,
|
|
299
|
+
return [3 /*break*/, 4];
|
|
299
300
|
case 2:
|
|
300
301
|
e_2 = _a.sent();
|
|
301
|
-
this.
|
|
302
|
-
|
|
303
|
-
|
|
302
|
+
if (!this.cancelDisconnectEvent) {
|
|
303
|
+
this.handleDisconnect("heartbeat");
|
|
304
|
+
}
|
|
305
|
+
return [3 /*break*/, 4];
|
|
306
|
+
case 3:
|
|
307
|
+
this.cancelDisconnectEvent = false;
|
|
308
|
+
return [7 /*endfinally*/];
|
|
309
|
+
case 4: return [2 /*return*/];
|
|
304
310
|
}
|
|
305
311
|
});
|
|
306
312
|
}); };
|
|
@@ -378,7 +384,7 @@ var Ableton = /** @class */ (function (_super) {
|
|
|
378
384
|
}
|
|
379
385
|
};
|
|
380
386
|
Ableton.prototype.handleUncompressedMessage = function (msg) {
|
|
381
|
-
var _a, _b;
|
|
387
|
+
var _a, _b, _c, _d;
|
|
382
388
|
this.emit("raw_message", msg);
|
|
383
389
|
var data = JSON.parse(msg);
|
|
384
390
|
var functionCallback = this.msgMap.get(data.uuid);
|
|
@@ -395,8 +401,11 @@ var Ableton = /** @class */ (function (_super) {
|
|
|
395
401
|
return this.handleDisconnect("realtime");
|
|
396
402
|
}
|
|
397
403
|
if (data.event === "connect") {
|
|
398
|
-
|
|
399
|
-
|
|
404
|
+
// If some heartbeat ping from the old connection is still pending,
|
|
405
|
+
// cancel it to prevent a double disconnect/connect event.
|
|
406
|
+
this.cancelDisconnectEvent = true;
|
|
407
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.port) && ((_b = data.data) === null || _b === void 0 ? void 0 : _b.port) !== this.serverPort) {
|
|
408
|
+
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.info("Got new server port via connect:", {
|
|
400
409
|
port: data.data.port,
|
|
401
410
|
});
|
|
402
411
|
this.serverPort = data.data.port;
|
|
@@ -409,7 +418,7 @@ var Ableton = /** @class */ (function (_super) {
|
|
|
409
418
|
}
|
|
410
419
|
if (data.uuid) {
|
|
411
420
|
this.emit("error", "Message could not be assigned to any request: " + msg);
|
|
412
|
-
(
|
|
421
|
+
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.warn("Message could not be assigned to any request:", {
|
|
413
422
|
msg: msg,
|
|
414
423
|
});
|
|
415
424
|
}
|
package/midi-script/Interface.py
CHANGED
|
@@ -90,7 +90,8 @@ class Interface(object):
|
|
|
90
90
|
value = self.get_prop(ns, prop)
|
|
91
91
|
return self.socket.send(eventId, value)
|
|
92
92
|
|
|
93
|
-
self.log_message("Attaching listener"
|
|
93
|
+
self.log_message("Attaching listener: " +
|
|
94
|
+
key + ", event ID: " + eventId)
|
|
94
95
|
add_fn(fn)
|
|
95
96
|
self.listeners[key] = {"id": eventId, "fn": fn}
|
|
96
97
|
return eventId
|
package/midi-script/Internal.py
CHANGED
package/midi-script/Socket.py
CHANGED
|
@@ -35,51 +35,90 @@ class Socket(object):
|
|
|
35
35
|
|
|
36
36
|
def __init__(self, handler):
|
|
37
37
|
self.input_handler = handler
|
|
38
|
-
self._server_addr = (
|
|
39
|
-
self._client_addr = (
|
|
38
|
+
self._server_addr = ("0.0.0.0", 0)
|
|
39
|
+
self._client_addr = ("127.0.0.1", 39031)
|
|
40
|
+
self._socket = None
|
|
41
|
+
|
|
40
42
|
self.read_remote_port()
|
|
41
|
-
self.init_socket()
|
|
43
|
+
self.init_socket(True)
|
|
44
|
+
|
|
45
|
+
self.file_timer = Live.Base.Timer(callback=self.read_remote_port,
|
|
46
|
+
interval=1000, repeat=True)
|
|
47
|
+
self.file_timer.start()
|
|
48
|
+
|
|
49
|
+
def read_last_server_port(self):
|
|
50
|
+
try:
|
|
51
|
+
with open(server_port_path) as file:
|
|
52
|
+
port = int(file.read())
|
|
53
|
+
|
|
54
|
+
self.log_message("Stored server port: " + str(port))
|
|
55
|
+
return port
|
|
56
|
+
except Exception as e:
|
|
57
|
+
self.log_message(
|
|
58
|
+
"Couldn't read stored server port: " + str(e.args))
|
|
59
|
+
return None
|
|
42
60
|
|
|
43
61
|
def read_remote_port(self):
|
|
44
62
|
'''Reads the port our client is listening on'''
|
|
45
63
|
try:
|
|
64
|
+
old_port = self._client_addr[1]
|
|
65
|
+
|
|
46
66
|
with open(client_port_path) as file:
|
|
47
67
|
port = int(file.read())
|
|
48
|
-
if port != self._client_addr[1]:
|
|
49
|
-
self.log_message("Client port changed: " + str(port))
|
|
50
|
-
self._client_addr = ('127.0.0.1', port)
|
|
51
68
|
|
|
52
|
-
|
|
69
|
+
if port != old_port:
|
|
70
|
+
self.log_message("[" + str(id(self)) + "] Client port changed from " +
|
|
71
|
+
str(old_port) + " to " + str(port))
|
|
72
|
+
self._client_addr = ("127.0.0.1", port)
|
|
73
|
+
|
|
74
|
+
if self._socket:
|
|
53
75
|
self.send("connect", {"port": self._server_addr[1]})
|
|
54
76
|
except Exception as e:
|
|
55
|
-
self.log_message("Couldn't read
|
|
56
|
-
|
|
57
|
-
t = Timer(1, self.read_remote_port)
|
|
58
|
-
t.start()
|
|
59
|
-
|
|
60
|
-
def init_socket(self):
|
|
61
|
-
self._socket = socket.socket(
|
|
62
|
-
socket.AF_INET, socket.SOCK_DGRAM)
|
|
63
|
-
self._socket.setblocking(0)
|
|
64
|
-
|
|
65
|
-
self.bind()
|
|
77
|
+
self.log_message("Couldn't read file: " + str(e.args))
|
|
66
78
|
|
|
67
79
|
def shutdown(self):
|
|
80
|
+
self.log_message("Shutting down...")
|
|
81
|
+
self.file_timer.stop()
|
|
68
82
|
self._socket.close()
|
|
69
83
|
|
|
70
|
-
def
|
|
84
|
+
def init_socket(self, try_stored=False):
|
|
85
|
+
self.log_message(
|
|
86
|
+
"Initializing socket, from stored: " + str(try_stored))
|
|
87
|
+
|
|
71
88
|
try:
|
|
89
|
+
stored_port = self.read_last_server_port()
|
|
90
|
+
|
|
91
|
+
# Try the port we used last time first
|
|
92
|
+
if try_stored and stored_port:
|
|
93
|
+
self._server_addr = ("0.0.0.0", stored_port)
|
|
94
|
+
else:
|
|
95
|
+
self._server_addr = ("0.0.0.0", 0)
|
|
96
|
+
|
|
97
|
+
self._socket = socket.socket(
|
|
98
|
+
socket.AF_INET, socket.SOCK_DGRAM)
|
|
99
|
+
self._socket.setblocking(0)
|
|
72
100
|
self._socket.bind(self._server_addr)
|
|
73
101
|
port = self._socket.getsockname()[1]
|
|
74
102
|
|
|
75
103
|
# Write the chosen port to a file
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
104
|
+
try:
|
|
105
|
+
if stored_port != port:
|
|
106
|
+
with open(server_port_path, "w") as file:
|
|
107
|
+
file.write(str(port))
|
|
108
|
+
except Exception as e:
|
|
109
|
+
self.log_message("Couldn't save port in file: " + str(e.args))
|
|
110
|
+
raise e
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
self.send("connect", {"port": self._server_addr[1]})
|
|
114
|
+
except Exception as e:
|
|
115
|
+
self.log_message("Couldn't send connect to " +
|
|
116
|
+
str(self._client_addr) + ": " + str(e.args))
|
|
117
|
+
|
|
118
|
+
self.show_message("Started server on port " + str(port))
|
|
119
|
+
|
|
120
|
+
self.log_message('Started server on: ' + str(self._socket.getsockname()) +
|
|
121
|
+
', client addr: ' + str(self._client_addr))
|
|
83
122
|
except Exception as e:
|
|
84
123
|
msg = 'ERROR: Cannot bind to ' + \
|
|
85
124
|
str(self._server_addr) + ': ' + \
|
|
@@ -87,7 +126,8 @@ class Socket(object):
|
|
|
87
126
|
'If this keeps happening, try restarting your computer.'
|
|
88
127
|
self.show_message(msg)
|
|
89
128
|
self.log_message(msg)
|
|
90
|
-
|
|
129
|
+
self.log_message("Client address: " + str(self._client_addr))
|
|
130
|
+
t = Timer(5, self.init_socket)
|
|
91
131
|
t.start()
|
|
92
132
|
|
|
93
133
|
def _sendto(self, msg):
|
|
@@ -112,14 +152,16 @@ class Socket(object):
|
|
|
112
152
|
return list(o)
|
|
113
153
|
return str(o)
|
|
114
154
|
|
|
155
|
+
data = None
|
|
156
|
+
|
|
115
157
|
try:
|
|
116
|
-
|
|
117
|
-
{"event": name, "data": obj, "uuid": uuid}, default=jsonReplace, ensure_ascii=False)
|
|
158
|
+
data = json.dumps(
|
|
159
|
+
{"event": name, "data": obj, "uuid": uuid}, default=jsonReplace, ensure_ascii=False)
|
|
160
|
+
self._sendto(data)
|
|
118
161
|
except socket.error as e:
|
|
119
|
-
self.log_message("Socket error: " + str(e.args))
|
|
120
|
-
|
|
121
|
-
self.
|
|
122
|
-
self.init_socket()
|
|
162
|
+
self.log_message("Socket error: " + str(e.args) + ", server: " + str(self._server_addr) +
|
|
163
|
+
", client: " + str(self._client_addr) + ", socket: " + str(self._socket))
|
|
164
|
+
self.log_message("Data:" + data)
|
|
123
165
|
except Exception as e:
|
|
124
166
|
error = str(type(e).__name__) + ': ' + str(e.args)
|
|
125
167
|
self.log_message("Error " + name + "(" + str(uuid) + "): " + error)
|
|
@@ -142,6 +184,8 @@ class Socket(object):
|
|
|
142
184
|
buffer = bytes()
|
|
143
185
|
num_messages = 0
|
|
144
186
|
except socket.error as e:
|
|
187
|
+
if (e.errno != 35):
|
|
188
|
+
self.log_message("Socket error: " + str(e.args))
|
|
145
189
|
return
|
|
146
190
|
except Exception as e:
|
|
147
191
|
self.log_message("Error while processing: " + str(e.args))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ableton-js",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "Control Ableton Live from Node",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Leo Bernard <admin@leolabs.org>",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"ableton10:launch": "set -- /Applications/Ableton*10* && open \"$1\"",
|
|
21
21
|
"ableton11:copy-script": "set -- /Applications/Ableton*11*/Contents/App-Resources/MIDI\\ Remote\\ Scripts && rm -rf \"$1/AbletonJS\" && cp -r \"$(pwd)/midi-script\" \"$1/AbletonJS\" && rm -rf \"$1/AbletonJS/_Framework\"",
|
|
22
22
|
"ableton11:launch": "set -- /Applications/Ableton*11* && open \"$1\"",
|
|
23
|
-
"ableton:logs": "tail -f ~/Library/Preferences/Ableton/*/Log.txt | grep -i -e RemoteScriptError -e RemoteScriptMessage",
|
|
23
|
+
"ableton:logs": "tail -n 50 -f ~/Library/Preferences/Ableton/*/Log.txt | grep -i -e RemoteScriptError -e RemoteScriptMessage",
|
|
24
24
|
"ableton:kill": "pkill -KILL -f \"Ableton Live\"",
|
|
25
25
|
"ableton10:start": "yarn ableton:kill; yarn ableton:clean && yarn ableton10:copy-script && yarn ableton10:launch && yarn ableton:logs",
|
|
26
26
|
"ableton11:start": "yarn ableton:kill; yarn ableton:clean && yarn ableton11:copy-script && yarn ableton11:launch && yarn ableton:logs",
|