ableton-js 3.2.10 → 3.3.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 +16 -0
- package/README.md +5 -5
- package/index.js +1 -3
- package/midi-script/AbletonJS.py +20 -0
- package/midi-script/Browser.py +66 -0
- package/midi-script/BrowserItem.py +26 -0
- package/midi-script/Socket.py +9 -6
- package/midi-script/Song.py +9 -0
- package/midi-script/version.py +1 -1
- package/ns/application.d.ts +4 -0
- package/ns/application.js +2 -0
- package/ns/browser-item.d.ts +34 -0
- package/ns/browser-item.js +25 -0
- package/ns/browser.d.ts +55 -0
- package/ns/browser.js +58 -0
- package/ns/song.d.ts +7 -0
- package/ns/song.js +10 -1
- 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.3.0](https://github.com/leolabs/ableton.js/compare/v3.2.11...v3.3.0)
|
|
8
|
+
|
|
9
|
+
- Browsing and loading functionalities [`bc48c7c`](https://github.com/leolabs/ableton.js/commit/bc48c7c46c55c54baca42c58003865596370afe3)
|
|
10
|
+
- :art: Improve formatting [`6e2e22b`](https://github.com/leolabs/ableton.js/commit/6e2e22b102cf560d39c07e60ae1afd7e2ecc851b)
|
|
11
|
+
- :sparkles: Turn the browser into a singleton [`6d0152b`](https://github.com/leolabs/ableton.js/commit/6d0152b4610683460256951801ada08f8598abeb)
|
|
12
|
+
|
|
13
|
+
#### [v3.2.11](https://github.com/leolabs/ableton.js/compare/v3.2.10...v3.2.11)
|
|
14
|
+
|
|
15
|
+
> 15 July 2023
|
|
16
|
+
|
|
17
|
+
- :loud_sound: Warn when the UDP tick is lagging or when processing UDP takes too long to finish [`c419afc`](https://github.com/leolabs/ableton.js/commit/c419afc96de5b5834ae2807baf8fc4b3fb9c21ba)
|
|
18
|
+
- :sparkles: Use larger buffer sizes if possible for sending responses from Live [`ae480cb`](https://github.com/leolabs/ableton.js/commit/ae480cb6e86fcbbb4e0417b0869a5a78d43511c6)
|
|
19
|
+
- :memo: Update docs to reflect that chunks now have a dynamic size [`83afbb6`](https://github.com/leolabs/ableton.js/commit/83afbb6431a28883fdc459e31081b94bd9c6b54a)
|
|
20
|
+
|
|
7
21
|
#### [v3.2.10](https://github.com/leolabs/ableton.js/compare/v3.2.9...v3.2.10)
|
|
8
22
|
|
|
23
|
+
> 15 July 2023
|
|
24
|
+
|
|
9
25
|
- :sparkles: Remove the socket after closing it to avoid dangling event listeners trying to send messages after the plugin has been shut down [`54278f2`](https://github.com/leolabs/ableton.js/commit/54278f2b4ccb6efe34592fc108cd10c35e404e58)
|
|
10
26
|
|
|
11
27
|
#### [v3.2.9](https://github.com/leolabs/ableton.js/compare/v3.2.8...v3.2.9)
|
package/README.md
CHANGED
|
@@ -103,11 +103,11 @@ port in a local file so the other side knows which port to send messages to.
|
|
|
103
103
|
### Compression and Chunking
|
|
104
104
|
|
|
105
105
|
To allow sending large JSON payloads, requests to and responses from the MIDI
|
|
106
|
-
Script are compressed using gzip and chunked
|
|
107
|
-
every message contains the chunk index
|
|
108
|
-
chunk. The last chunk always has the index
|
|
109
|
-
library that the previous received messages
|
|
110
|
-
unzipped, and processed.
|
|
106
|
+
Script are compressed using gzip and chunked to fit into the maximum allowed
|
|
107
|
+
package size. The first byte of every message chunk contains the chunk index
|
|
108
|
+
(0x00-0xFF) followed by the gzipped chunk. The last chunk always has the index
|
|
109
|
+
0xFF. This indicates to the JS library that the previous received messages
|
|
110
|
+
should be stiched together, unzipped, and processed.
|
|
111
111
|
|
|
112
112
|
### Caching
|
|
113
113
|
|
package/index.js
CHANGED
|
@@ -434,9 +434,7 @@ class Ableton extends events_1.EventEmitter {
|
|
|
434
434
|
throw new Error("The client hasn't been started yet. Please call start() first.");
|
|
435
435
|
}
|
|
436
436
|
const buffer = (0, zlib_1.deflateSync)(Buffer.from(msg));
|
|
437
|
-
|
|
438
|
-
// https://stackoverflow.com/questions/22819214/udp-message-too-long
|
|
439
|
-
const byteLimit = 7500;
|
|
437
|
+
const byteLimit = this.client.getSendBufferSize() - 1;
|
|
440
438
|
const chunks = Math.ceil(buffer.byteLength / byteLimit);
|
|
441
439
|
// Split the message into chunks if it becomes too large
|
|
442
440
|
for (let i = 0; i < chunks; i++) {
|
package/midi-script/AbletonJS.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
|
+
import time
|
|
2
3
|
|
|
3
4
|
from .version import version
|
|
4
5
|
from .Config import DEBUG, FAST_POLLING
|
|
@@ -6,6 +7,8 @@ from .Socket import Socket
|
|
|
6
7
|
from .Interface import Interface
|
|
7
8
|
from .Application import Application
|
|
8
9
|
from .ApplicationView import ApplicationView
|
|
10
|
+
from .Browser import Browser
|
|
11
|
+
from .BrowserItem import BrowserItem
|
|
9
12
|
from .CuePoint import CuePoint
|
|
10
13
|
from .Device import Device
|
|
11
14
|
from .DeviceParameter import DeviceParameter
|
|
@@ -37,6 +40,8 @@ class AbletonJS(ControlSurface):
|
|
|
37
40
|
self.handlers = {
|
|
38
41
|
"application": Application(c_instance, self.socket, self.application()),
|
|
39
42
|
"application-view": ApplicationView(c_instance, self.socket, self.application()),
|
|
43
|
+
"browser": Browser(c_instance, self.socket, self.application()),
|
|
44
|
+
"browser-item": BrowserItem(c_instance, self.socket),
|
|
40
45
|
"cue-point": CuePoint(c_instance, self.socket),
|
|
41
46
|
"device": Device(c_instance, self.socket),
|
|
42
47
|
"device-parameter": DeviceParameter(c_instance, self.socket),
|
|
@@ -51,6 +56,7 @@ class AbletonJS(ControlSurface):
|
|
|
51
56
|
"clip": Clip(c_instance, self.socket),
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
self._last_tick = time.time() * 1000
|
|
54
60
|
self.tick()
|
|
55
61
|
|
|
56
62
|
if FAST_POLLING:
|
|
@@ -60,7 +66,21 @@ class AbletonJS(ControlSurface):
|
|
|
60
66
|
self.recv_loop.start()
|
|
61
67
|
|
|
62
68
|
def tick(self):
|
|
69
|
+
tick_time = time.time() * 1000
|
|
70
|
+
|
|
71
|
+
if tick_time - self._last_tick > 200:
|
|
72
|
+
self.log_message("UDP tick is lagging, delta: " +
|
|
73
|
+
str(round(tick_time - self._last_tick)) + "ms")
|
|
74
|
+
|
|
75
|
+
self._last_tick = tick_time
|
|
63
76
|
self.socket.process()
|
|
77
|
+
|
|
78
|
+
process_time = time.time() * 1000
|
|
79
|
+
|
|
80
|
+
if process_time - tick_time > 100:
|
|
81
|
+
self.log_message("UDP processing is taking long, delta: " +
|
|
82
|
+
str(round(tick_time - process_time)) + "ms")
|
|
83
|
+
|
|
64
84
|
self.schedule_message(1, self.tick)
|
|
65
85
|
|
|
66
86
|
def build_midi_map(self, midi_map_handle):
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
from .Interface import Interface
|
|
3
|
+
from .BrowserItem import BrowserItem
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Browser(Interface):
|
|
7
|
+
def __init__(self, c_instance, socket, application):
|
|
8
|
+
super(Browser, self).__init__(c_instance, socket)
|
|
9
|
+
self.application = application
|
|
10
|
+
|
|
11
|
+
def get_ns(self, nsid=None):
|
|
12
|
+
return self.application.browser
|
|
13
|
+
|
|
14
|
+
def get_audio_effects(self, ns):
|
|
15
|
+
return map(BrowserItem.serialize_browser_item, ns.audio_effects.children)
|
|
16
|
+
|
|
17
|
+
def get_clips(self, ns):
|
|
18
|
+
return map(BrowserItem.serialize_browser_item, ns.clips.children)
|
|
19
|
+
|
|
20
|
+
def get_colors(self, ns):
|
|
21
|
+
return map(BrowserItem.serialize_browser_item, ns.colors)
|
|
22
|
+
|
|
23
|
+
def get_current_project(self, ns):
|
|
24
|
+
return map(BrowserItem.serialize_browser_item, ns.current_project.children)
|
|
25
|
+
|
|
26
|
+
def get_drums(self, ns):
|
|
27
|
+
return map(BrowserItem.serialize_browser_item, ns.drums.children)
|
|
28
|
+
|
|
29
|
+
def get_instruments(self, ns):
|
|
30
|
+
return map(BrowserItem.serialize_browser_item, ns.instruments.children)
|
|
31
|
+
|
|
32
|
+
def get_max_for_live(self, ns):
|
|
33
|
+
return map(BrowserItem.serialize_browser_item, ns.max_for_live.children)
|
|
34
|
+
|
|
35
|
+
def get_midi_effects(self, ns):
|
|
36
|
+
return map(BrowserItem.serialize_browser_item, ns.midi_effects.children)
|
|
37
|
+
|
|
38
|
+
def get_packs(self, ns):
|
|
39
|
+
return map(BrowserItem.serialize_browser_item, ns.packs.children)
|
|
40
|
+
|
|
41
|
+
def get_plugins(self, ns):
|
|
42
|
+
return map(BrowserItem.serialize_browser_item, ns.plugins.children)
|
|
43
|
+
|
|
44
|
+
def get_samples(self, ns):
|
|
45
|
+
return map(BrowserItem.serialize_browser_item, ns.samples.children)
|
|
46
|
+
|
|
47
|
+
def get_sounds(self, ns):
|
|
48
|
+
return map(BrowserItem.serialize_browser_item, ns.sounds.children)
|
|
49
|
+
|
|
50
|
+
def get_user_folders(self, ns):
|
|
51
|
+
return map(BrowserItem.serialize_browser_item, ns.user_folders)
|
|
52
|
+
|
|
53
|
+
def get_user_library(self, ns):
|
|
54
|
+
return map(BrowserItem.serialize_browser_item, ns.user_library.children)
|
|
55
|
+
|
|
56
|
+
def get_hotswap_target(self, ns):
|
|
57
|
+
return BrowserItem.serialize_browser_item(ns.hotswap_target)
|
|
58
|
+
|
|
59
|
+
def load_item(self, ns, id):
|
|
60
|
+
return ns.load_item(self.get_obj(id))
|
|
61
|
+
|
|
62
|
+
def preview_item(self, ns, id):
|
|
63
|
+
return ns.preview_item(self.get_obj(id))
|
|
64
|
+
|
|
65
|
+
def stop_preview(self, ns):
|
|
66
|
+
return ns.stop_preview()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
from .Interface import Interface
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BrowserItem(Interface):
|
|
6
|
+
@staticmethod
|
|
7
|
+
def serialize_browser_item(browser_item):
|
|
8
|
+
if browser_item is None:
|
|
9
|
+
return None
|
|
10
|
+
browser_item_id = Interface.save_obj(browser_item)
|
|
11
|
+
return {
|
|
12
|
+
"id": browser_item_id,
|
|
13
|
+
"name": browser_item.name,
|
|
14
|
+
"is_loadable": browser_item.is_loadable,
|
|
15
|
+
"is_selected": browser_item.is_selected,
|
|
16
|
+
"is_device": browser_item.is_device,
|
|
17
|
+
"is_folder": browser_item.is_folder,
|
|
18
|
+
"source": browser_item.source,
|
|
19
|
+
"uri": browser_item.uri,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def __init__(self, c_instance, socket):
|
|
23
|
+
super(BrowserItem, self).__init__(c_instance, socket)
|
|
24
|
+
|
|
25
|
+
def get_children(self, ns):
|
|
26
|
+
return map(BrowserItem.serialize_browser_item, ns.children)
|
package/midi-script/Socket.py
CHANGED
|
@@ -114,6 +114,12 @@ class Socket(object):
|
|
|
114
114
|
self._socket.bind(self._server_addr)
|
|
115
115
|
port = self._socket.getsockname()[1]
|
|
116
116
|
|
|
117
|
+
# Get the chunk limit of the socket, minus 1 for the ordering byte
|
|
118
|
+
self._chunk_limit = self._socket.getsockopt(
|
|
119
|
+
socket.SOL_SOCKET, socket.SO_SNDBUF) - 1
|
|
120
|
+
|
|
121
|
+
self.log_message("Chunk limit: " + str(self._chunk_limit))
|
|
122
|
+
|
|
117
123
|
# Write the chosen port to a file
|
|
118
124
|
try:
|
|
119
125
|
if stored_port != port:
|
|
@@ -147,17 +153,14 @@ class Socket(object):
|
|
|
147
153
|
def _sendto(self, msg):
|
|
148
154
|
'''Send a raw message to the client, compressed and chunked, if necessary'''
|
|
149
155
|
compressed = zlib.compress(msg.encode("utf8")) + b'\n'
|
|
150
|
-
# Based on this thread, 7500 bytes seems like a safe value
|
|
151
|
-
# https://stackoverflow.com/questions/22819214/udp-message-too-long
|
|
152
|
-
limit = 7500
|
|
153
156
|
|
|
154
157
|
if self._socket == None:
|
|
155
158
|
return
|
|
156
159
|
|
|
157
|
-
if len(compressed) <
|
|
160
|
+
if len(compressed) < self._chunk_limit:
|
|
158
161
|
self._socket.sendto(b'\xFF' + compressed, self._client_addr)
|
|
159
162
|
else:
|
|
160
|
-
chunks = list(split_by_n(compressed,
|
|
163
|
+
chunks = list(split_by_n(compressed, self._chunk_limit))
|
|
161
164
|
count = len(chunks)
|
|
162
165
|
for i, chunk in enumerate(chunks):
|
|
163
166
|
count_byte = struct.pack("B", i if i + 1 < count else 255)
|
|
@@ -188,7 +191,7 @@ class Socket(object):
|
|
|
188
191
|
buffer = bytes()
|
|
189
192
|
num_messages = 0
|
|
190
193
|
while 1:
|
|
191
|
-
data = self._socket.recv(
|
|
194
|
+
data = self._socket.recv(65536)
|
|
192
195
|
if len(data) and self.input_handler:
|
|
193
196
|
buffer += data[1:]
|
|
194
197
|
num_messages += 1
|
package/midi-script/Song.py
CHANGED
|
@@ -4,12 +4,17 @@ from .CuePoint import CuePoint
|
|
|
4
4
|
from .Device import Device
|
|
5
5
|
from .Scene import Scene
|
|
6
6
|
from .Track import Track
|
|
7
|
+
import Live
|
|
7
8
|
|
|
9
|
+
INSERT_MODES = {'default':Live.Track.DeviceInsertMode.default,
|
|
10
|
+
'left':Live.Track.DeviceInsertMode.selected_left,
|
|
11
|
+
'right':Live.Track.DeviceInsertMode.selected_right}
|
|
8
12
|
|
|
9
13
|
class Song(Interface):
|
|
10
14
|
def __init__(self, c_instance, socket):
|
|
11
15
|
super(Song, self).__init__(c_instance, socket)
|
|
12
16
|
self.song = self.ableton.song()
|
|
17
|
+
self._insert_mode = INSERT_MODES['default']
|
|
13
18
|
|
|
14
19
|
def get_ns(self, nsid):
|
|
15
20
|
return self.song
|
|
@@ -60,3 +65,7 @@ class Song(Interface):
|
|
|
60
65
|
|
|
61
66
|
def set_appointed_device(self, ns, device_id):
|
|
62
67
|
ns.appointed_device = Interface.get_obj(device_id)
|
|
68
|
+
|
|
69
|
+
def set_insert_mode(self,ns, args):
|
|
70
|
+
self._insert_mode = INSERT_MODES.get(str(args), INSERT_MODES['default'])
|
|
71
|
+
self.song.view.selected_track.view.device_insert_mode = self._insert_mode
|
package/midi-script/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "3.
|
|
1
|
+
version = "3.3.0"
|
package/ns/application.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Ableton } from "..";
|
|
2
2
|
import { Namespace } from ".";
|
|
3
3
|
import { ApplicationView } from "./application-view";
|
|
4
|
+
import { Browser, RawBrowser } from "./browser";
|
|
4
5
|
export interface GettableProperties {
|
|
5
6
|
bugfix_version: number;
|
|
6
7
|
major_version: number;
|
|
@@ -9,8 +10,10 @@ export interface GettableProperties {
|
|
|
9
10
|
current_dialog_button_count: number;
|
|
10
11
|
current_dialog_message: string;
|
|
11
12
|
open_dialog_count: number;
|
|
13
|
+
browser: RawBrowser;
|
|
12
14
|
}
|
|
13
15
|
export interface TransformedProperties {
|
|
16
|
+
browser: Browser;
|
|
14
17
|
}
|
|
15
18
|
export interface SettableProperties {
|
|
16
19
|
}
|
|
@@ -19,6 +22,7 @@ export interface ObservableProperties {
|
|
|
19
22
|
}
|
|
20
23
|
export declare class Application extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
21
24
|
constructor(ableton: Ableton);
|
|
25
|
+
browser: Browser;
|
|
22
26
|
view: ApplicationView;
|
|
23
27
|
pressCurrentDialogButton(index: number): Promise<any>;
|
|
24
28
|
}
|
package/ns/application.js
CHANGED
|
@@ -3,10 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Application = void 0;
|
|
4
4
|
const _1 = require(".");
|
|
5
5
|
const application_view_1 = require("./application-view");
|
|
6
|
+
const browser_1 = require("./browser");
|
|
6
7
|
class Application extends _1.Namespace {
|
|
7
8
|
constructor(ableton) {
|
|
8
9
|
super(ableton, "application");
|
|
9
10
|
}
|
|
11
|
+
browser = new browser_1.Browser(this.ableton);
|
|
10
12
|
view = new application_view_1.ApplicationView(this.ableton);
|
|
11
13
|
async pressCurrentDialogButton(index) {
|
|
12
14
|
return this.sendCommand("press_current_dialog_button", [index]);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Ableton } from "..";
|
|
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
|
+
export interface GettableProperties {
|
|
15
|
+
children: RawBrowserItem[];
|
|
16
|
+
is_device: boolean;
|
|
17
|
+
is_folder: boolean;
|
|
18
|
+
is_loadable: boolean;
|
|
19
|
+
is_selected: boolean;
|
|
20
|
+
name: string;
|
|
21
|
+
source: string;
|
|
22
|
+
uri: string;
|
|
23
|
+
}
|
|
24
|
+
export interface TransformedProperties {
|
|
25
|
+
children: BrowserItem[];
|
|
26
|
+
}
|
|
27
|
+
export interface SettableProperties {
|
|
28
|
+
}
|
|
29
|
+
export interface ObservableProperties {
|
|
30
|
+
}
|
|
31
|
+
export declare class BrowserItem extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
32
|
+
raw: RawBrowserItem;
|
|
33
|
+
constructor(ableton: Ableton, raw: RawBrowserItem);
|
|
34
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BrowserItem = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
class BrowserItem extends _1.Namespace {
|
|
6
|
+
raw;
|
|
7
|
+
constructor(ableton, raw) {
|
|
8
|
+
super(ableton, "browser-item", raw.id);
|
|
9
|
+
this.raw = raw;
|
|
10
|
+
this.transformers = {
|
|
11
|
+
children: (children) => children.map((c) => new BrowserItem(ableton, c)),
|
|
12
|
+
};
|
|
13
|
+
this.cachedProps = {
|
|
14
|
+
children: true,
|
|
15
|
+
is_device: true,
|
|
16
|
+
is_folder: true,
|
|
17
|
+
is_loadable: false,
|
|
18
|
+
is_selected: false,
|
|
19
|
+
name: true,
|
|
20
|
+
source: true,
|
|
21
|
+
uri: true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.BrowserItem = BrowserItem;
|
package/ns/browser.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Ableton } from "..";
|
|
2
|
+
import { Namespace } from ".";
|
|
3
|
+
import { BrowserItem, RawBrowserItem } from "./browser-item";
|
|
4
|
+
export interface GettableProperties {
|
|
5
|
+
audio_effects: RawBrowserItem[];
|
|
6
|
+
clips: RawBrowserItem[];
|
|
7
|
+
colors: RawBrowserItem[];
|
|
8
|
+
current_project: RawBrowserItem[];
|
|
9
|
+
drums: RawBrowserItem[];
|
|
10
|
+
instruments: RawBrowserItem[];
|
|
11
|
+
max_for_live: RawBrowserItem[];
|
|
12
|
+
midi_effects: RawBrowserItem[];
|
|
13
|
+
packs: RawBrowserItem[];
|
|
14
|
+
plugins: RawBrowserItem[];
|
|
15
|
+
samples: RawBrowserItem[];
|
|
16
|
+
sounds: RawBrowserItem[];
|
|
17
|
+
user_library: RawBrowserItem[];
|
|
18
|
+
user_folders: RawBrowserItem[];
|
|
19
|
+
hotswap_target: RawBrowserItem;
|
|
20
|
+
}
|
|
21
|
+
export interface TransformedProperties {
|
|
22
|
+
audio_effects: BrowserItem[];
|
|
23
|
+
clips: BrowserItem[];
|
|
24
|
+
colors: BrowserItem[];
|
|
25
|
+
current_project: BrowserItem[];
|
|
26
|
+
drums: BrowserItem[];
|
|
27
|
+
instruments: BrowserItem[];
|
|
28
|
+
max_for_live: BrowserItem[];
|
|
29
|
+
midi_effects: BrowserItem[];
|
|
30
|
+
packs: BrowserItem[];
|
|
31
|
+
plugins: BrowserItem[];
|
|
32
|
+
samples: BrowserItem[];
|
|
33
|
+
sounds: BrowserItem[];
|
|
34
|
+
user_library: BrowserItem[];
|
|
35
|
+
user_folders: BrowserItem[];
|
|
36
|
+
hotswap_target: BrowserItem;
|
|
37
|
+
}
|
|
38
|
+
export interface SettableProperties {
|
|
39
|
+
}
|
|
40
|
+
export interface ObservableProperties {
|
|
41
|
+
filter_type: never;
|
|
42
|
+
hotswap_target: BrowserItem;
|
|
43
|
+
}
|
|
44
|
+
export interface RawBrowser {
|
|
45
|
+
id: string;
|
|
46
|
+
}
|
|
47
|
+
export declare class Browser extends Namespace<GettableProperties, TransformedProperties, SettableProperties, ObservableProperties> {
|
|
48
|
+
constructor(ableton: Ableton);
|
|
49
|
+
/** Loads the provided browser item. */
|
|
50
|
+
loadItem(item: BrowserItem): Promise<any>;
|
|
51
|
+
/** Previews the provided browser item. */
|
|
52
|
+
previewItem(item: BrowserItem): Promise<any>;
|
|
53
|
+
/** Stops the current preview. */
|
|
54
|
+
stopPreview(): Promise<any>;
|
|
55
|
+
}
|
package/ns/browser.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Browser = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
const browser_item_1 = require("./browser-item");
|
|
6
|
+
class Browser extends _1.Namespace {
|
|
7
|
+
constructor(ableton) {
|
|
8
|
+
super(ableton, "browser");
|
|
9
|
+
const makeBrowserItems = (items) => items.map((item) => new browser_item_1.BrowserItem(ableton, item));
|
|
10
|
+
this.transformers = {
|
|
11
|
+
audio_effects: makeBrowserItems,
|
|
12
|
+
clips: makeBrowserItems,
|
|
13
|
+
colors: makeBrowserItems,
|
|
14
|
+
current_project: makeBrowserItems,
|
|
15
|
+
drums: makeBrowserItems,
|
|
16
|
+
instruments: makeBrowserItems,
|
|
17
|
+
max_for_live: makeBrowserItems,
|
|
18
|
+
midi_effects: makeBrowserItems,
|
|
19
|
+
packs: makeBrowserItems,
|
|
20
|
+
plugins: makeBrowserItems,
|
|
21
|
+
samples: makeBrowserItems,
|
|
22
|
+
sounds: makeBrowserItems,
|
|
23
|
+
user_library: makeBrowserItems,
|
|
24
|
+
user_folders: makeBrowserItems,
|
|
25
|
+
hotswap_target: (t) => new browser_item_1.BrowserItem(ableton, t),
|
|
26
|
+
};
|
|
27
|
+
this.cachedProps = {
|
|
28
|
+
audio_effects: true,
|
|
29
|
+
clips: true,
|
|
30
|
+
colors: true,
|
|
31
|
+
current_project: true,
|
|
32
|
+
drums: true,
|
|
33
|
+
instruments: true,
|
|
34
|
+
max_for_live: true,
|
|
35
|
+
midi_effects: true,
|
|
36
|
+
packs: true,
|
|
37
|
+
plugins: true,
|
|
38
|
+
samples: true,
|
|
39
|
+
sounds: true,
|
|
40
|
+
user_library: true,
|
|
41
|
+
user_folders: true,
|
|
42
|
+
hotswap_target: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Loads the provided browser item. */
|
|
46
|
+
async loadItem(item) {
|
|
47
|
+
return this.sendCommand("load_item", { id: item.raw.id });
|
|
48
|
+
}
|
|
49
|
+
/** Previews the provided browser item. */
|
|
50
|
+
async previewItem(item) {
|
|
51
|
+
return this.sendCommand("preview_item", { id: item.raw.id });
|
|
52
|
+
}
|
|
53
|
+
/** Stops the current preview. */
|
|
54
|
+
async stopPreview() {
|
|
55
|
+
return this.sendCommand("stop_preview");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.Browser = Browser;
|
package/ns/song.d.ts
CHANGED
|
@@ -61,6 +61,11 @@ export interface TransformedProperties {
|
|
|
61
61
|
visible_tracks: Track[];
|
|
62
62
|
scenes: Scene[];
|
|
63
63
|
}
|
|
64
|
+
export declare enum DeviceInsertMode {
|
|
65
|
+
default = "default",
|
|
66
|
+
left = "left",
|
|
67
|
+
right = "right"
|
|
68
|
+
}
|
|
64
69
|
export interface SettableProperties {
|
|
65
70
|
appointed_device: string;
|
|
66
71
|
arrangement_overdub: boolean;
|
|
@@ -71,6 +76,7 @@ export interface SettableProperties {
|
|
|
71
76
|
exclusive_arm: number;
|
|
72
77
|
exclusive_solo: number;
|
|
73
78
|
groove_amount: number;
|
|
79
|
+
insert_mode: DeviceInsertMode;
|
|
74
80
|
is_counting_in: boolean;
|
|
75
81
|
is_playing: boolean;
|
|
76
82
|
last_event_time: number;
|
|
@@ -213,4 +219,5 @@ export declare class Song extends Namespace<GettableProperties, TransformedPrope
|
|
|
213
219
|
stopPlaying(): Promise<any>;
|
|
214
220
|
tapTempo(): Promise<any>;
|
|
215
221
|
undo(): Promise<any>;
|
|
222
|
+
set_insert_mode(args: DeviceInsertMode): Promise<any>;
|
|
216
223
|
}
|
package/ns/song.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Song = exports.RecordingQuantization = exports.Quantization = exports.TimeFormat = void 0;
|
|
3
|
+
exports.Song = exports.RecordingQuantization = exports.Quantization = exports.TimeFormat = exports.DeviceInsertMode = void 0;
|
|
4
4
|
const _1 = require(".");
|
|
5
5
|
const track_1 = require("./track");
|
|
6
6
|
const cue_point_1 = require("./cue-point");
|
|
7
7
|
const song_view_1 = require("./song-view");
|
|
8
8
|
const scene_1 = require("./scene");
|
|
9
|
+
var DeviceInsertMode;
|
|
10
|
+
(function (DeviceInsertMode) {
|
|
11
|
+
DeviceInsertMode["default"] = "default";
|
|
12
|
+
DeviceInsertMode["left"] = "left";
|
|
13
|
+
DeviceInsertMode["right"] = "right";
|
|
14
|
+
})(DeviceInsertMode || (exports.DeviceInsertMode = DeviceInsertMode = {}));
|
|
9
15
|
var TimeFormat;
|
|
10
16
|
(function (TimeFormat) {
|
|
11
17
|
TimeFormat[TimeFormat["MsTime"] = 0] = "MsTime";
|
|
@@ -149,5 +155,8 @@ class Song extends _1.Namespace {
|
|
|
149
155
|
async undo() {
|
|
150
156
|
return this.sendCommand("undo");
|
|
151
157
|
}
|
|
158
|
+
async set_insert_mode(args) {
|
|
159
|
+
return this.sendCommand("set_insert_mode", { args });
|
|
160
|
+
}
|
|
152
161
|
}
|
|
153
162
|
exports.Song = Song;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ableton-js",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Control Ableton Live from Node",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Leo Bernard <admin@leolabs.org>",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"ableton:copy-script": "set -- ~/Music/Ableton/User\\ Library/Remote\\ Scripts && mkdir -p \"$1\" && rm -rf \"$1/AbletonJS\" && cp -r \"$(pwd)/midi-script\" \"$1/AbletonJS\" && rm -rf \"$1/AbletonJS/_Framework\"",
|
|
20
20
|
"ableton10:launch": "set -- /Applications/Ableton*10* && open \"$1\"",
|
|
21
21
|
"ableton11:launch": "set -- /Applications/Ableton*11* && open \"$1\"",
|
|
22
|
-
"ableton:logs": "tail -n 50 -f ~/Library/Preferences/Ableton/*/Log.txt | grep -i -e RemoteScriptError -e RemoteScriptMessage",
|
|
22
|
+
"ableton:logs": "tail -n 50 -f ~/Library/Preferences/Ableton/*/Log.txt | grep --line-buffered -i -e RemoteScriptError -e RemoteScriptMessage | sed 's/info: RemoteScriptMessage: (AbletonJS) //'",
|
|
23
23
|
"ableton:kill": "pkill -KILL -f \"Ableton Live\"",
|
|
24
24
|
"ableton10:start": "yarn ableton:kill; yarn ableton:clean && yarn ableton:copy-script && yarn ableton10:launch && yarn ableton:logs",
|
|
25
25
|
"ableton11:start": "yarn ableton:kill; yarn ableton:clean && yarn ableton:copy-script && yarn ableton11:launch && yarn ableton:logs",
|