Browse Source

resize in presentation mode, more robust initialization, performance improvement, small bug fixes

main
TFLCL 5 months ago
parent
commit
8f4e7ff660
  1. 18
      README.md
  2. 124
      tc.preset.js
  3. 83
      tc.preset_demo.maxpat

18
README.md

@ -3,9 +3,10 @@
A [jsui] replacement for the [preset] object in Cycling'74 Max. A [jsui] replacement for the [preset] object in Cycling'74 Max.
## Features ## Features
- Same click + modifier key behavior as the vanilla object to store and delete presets
- Drag and drop presets to re-organize - Drag and drop presets to re-organize
- Display presets as a grid or a list - Display presets as a grid or a list
- Scrollable (requires Max 8.6.2) - Scrollable list layout (requires Max 8.6.2)
- Shows active preset even if recalled directly from pattrstorage - Shows active preset even if recalled directly from pattrstorage
- Shows previously active preset, with the ability to ignore preset 0 if it being used as an intermediary step - Shows previously active preset, with the ability to ignore preset 0 if it being used as an intermediary step
- Shows presets being interpolated (using recall or recallmulti) - Shows presets being interpolated (using recall or recallmulti)
@ -14,24 +15,27 @@ A [jsui] replacement for the [preset] object in Cycling'74 Max.
- Ability to rewrite json file automatically every time a preset is stored/moved/deleted/renamed/(un)locked - Ability to rewrite json file automatically every time a preset is stored/moved/deleted/renamed/(un)locked
- Helps keeping in sync a umenu with the list of stored slotstlet - Helps keeping in sync a umenu with the list of stored slotstlet
- More look customization - More look customization
- Same click + modifier key behavior as the vanilla object to store or delete presets - Dynamically adapts to resize both in Edit and Presentation mode
- Select mode: simple click selects the slot, double click recalls it (allows for organizing presets without recalling them)
- Color mode: ability to color sstored presets with 6 customizable colors (currently colors are only assigned automatically depending on slot number)
## How to use ## How to use
- Place `tc.preset.js` in the same directory as your patch, or somewhere in the Max search path - Place `tc.preset.js` in the same directory as your patch, or somewhere in the Max search path
- Create a [`jsui @filename tc.preset.js`]. You can either add `@jsarguments` followed by the name of the pattrstorage you want to communicate with, or set that later by sending a `pattrstorage` (followed by the pattrstorage name) message to the [jsui]. - Create a [`jsui @filename tc.preset.js`].
- Connect the [pattrstorage] outlet to the [jsui] inlet - Connect the [pattrstorage] outlet to the [jsui] inlet
- Set the jsui attribute named "pattrstorage" to the name of the pattrstorage you just connected (or send a message like "pattrstorage my_pattrstorage_name")
## Limitations ## Limitations
- Resize doesn't work in Presentation mode (jsui limitation)
- Due to the way [pattrstorage] works, some pattrstorage-specific messages should be sent to the [jsui] instead of the [pattrstorage]. Some to both: - Due to the way [pattrstorage] works, some pattrstorage-specific messages should be sent to the [jsui] instead of the [pattrstorage]. Some to both:
- `recall`, `delete`: send to [pattrstorage] only - `recall`: send to [pattrstorage] only
- `recallmulti`, `slotname`: send to [pattrstorage] first (for better timing), then to the [jsui] - `recallmulti`, `slotname`: send to [pattrstorage] first (for better timing), then to the [jsui]
- `store`: send to [jsui] only - `store`: send to [jsui] only
- Some messages to pattrstorage causes the jsui to be out of sync (`clear`, `insert`, `lockall`, `read`, `readagain`, `remove`, `renumber`). If you use any of these messages, make sure to then send a `resync` to the jsui. - Some messages to pattrstorage causes the jsui to be out of sync (`clear`, `insert`, `lockall`, `read`, `readagain`, `remove`, `renumber`). If you use any of these messages, make sure to then send a `resync` to the jsui.
- The js program send a lot of message to the [pattrstorage] (using `maxobj.message()`syntax, so without patch cord), which in return send (using a patch cord) a lot of messages required for the [jsui] to stay in sync. Using one of the above messages incorrectly, or sending `getslotlist`, `getslotnamelist`, or any message that will impact the presets might cause the [pattrstorage] to get out of sync. In case something like that happens, you can send the `resync` message to the [jsui]. - The js program send a lot of message to the [pattrstorage] (using `maxobj.message()`syntax, so without patch cord), which in return send (using a patch cord) a lot of messages required for the [jsui] to stay in sync. Using one of the above messages incorrectly, or sending `getslotlist`, `getslotnamelist`, or any message that will impact the presets might cause the [pattrstorage] to get out of sync. In case something like that happens, you can send the `resync` message to the [jsui].
## Desired features (for someday) ## Desired features (for someday, if ever)
- Select mode: simple click selects the slot, double click recalls it
- No need for a patch cord (programmatically create a [send]/[receive] pair?) - No need for a patch cord (programmatically create a [send]/[receive] pair?)
- Ability to lock/unlock and rename directly in the jsui without the need of external objects - Ability to lock/unlock and rename directly in the jsui without the need of external objects
- Ability to target a [pattrstorage] in a different patcher level - Ability to target a [pattrstorage] in a different patcher level

124
tc.preset.js

@ -106,18 +106,26 @@ var is_interpolating = 0;
var is_dragging = 0; // Drag flag var is_dragging = 0; // Drag flag
var drag_slot = -1; // Stores the slot that's being dragged var drag_slot = -1; // Stores the slot that's being dragged
if (jsarguments.length>1) { var has_loaded = false;
// Allows for dynamic resizing even in presentation mode (addressing the limitation of onresize())
var pres_rect = new MaxobjListener(this.box,"presentation_rect",get_prect);
function get_prect(prect) {
onresize(prect.value[2], prect.value[3])
}
if (jsarguments.length>1) { // Depreciated, use "pattrstorage" attribute instead of jsarguments.
pattrstorage_name = jsarguments[1]; pattrstorage_name = jsarguments[1];
} }
function loadbang() { function loadbang() {
has_loaded = true;
post("loadbang\n");
outlet(2, "set"); outlet(2, "set");
find_pattrstorage(pattrstorage_name); find_pattrstorage(pattrstorage_name);
calc_rows_columns(); calc_rows_columns();
} }
// loadbang();
function calc_rows_columns() { function calc_rows_columns() {
half_margin = margin / 2; half_margin = margin / 2;
half_spacing = spacing / 2; half_spacing = spacing / 2;
@ -246,6 +254,7 @@ function draw_text_bubble(x, y, w, h, text, cont) {
cont.move_to(txt_pos_x, txt_pos_y); cont.move_to(txt_pos_x, txt_pos_y);
cont.show_text(text.toString()); cont.show_text(text.toString());
} }
draw_text_bubble.local = 1;
function format_slot_name(id) { function format_slot_name(id) {
var text = id; var text = id;
@ -264,7 +273,7 @@ format_slot_name.local = 1;
function paint_base() { function paint_base() {
// We draw all slots (empty and stored ones) so we don't have to for every redraw // We draw all slots (empty and stored ones) so we don't have to for every redraw
// post("paint_base\n");
is_painting_base = 1; is_painting_base = 1;
// Background // Background
@ -305,6 +314,12 @@ paint_base.local = 1;
function paint() function paint()
{ {
// post("redraw\n"); // post("redraw\n");
// Handling Presentation mode enable/disable
var cur_size = mgraphics.size;
if (cur_size[0] != ui_width || cur_size[1] != ui_height) {
onresize(cur_size[0], cur_size[1]);
} else {
with (mgraphics) { with (mgraphics) {
select_font_face(font_name); select_font_face(font_name);
set_font_size(font_size); set_font_size(font_size);
@ -349,7 +364,7 @@ function paint()
} }
// Selected slot // Selected slot
if (select_mode && selected_slot > 0 && selected_slot <= slots_count_display) { if (selected_slot > 0 && selected_slot <= slots_count_display) {
set_source_rgba(active_slot_color); set_source_rgba(active_slot_color);
set_line_width(1); set_line_width(1);
draw_slot_bubble(slots[selected_slot][0] - 0.5, slots[selected_slot][1] - 0.5, slot_size + 1, slot_size + 1); draw_slot_bubble(slots[selected_slot][0] - 0.5, slots[selected_slot][1] - 0.5, slot_size + 1, slot_size + 1);
@ -467,6 +482,7 @@ function paint()
} }
} }
}
paint.local = 1; paint.local = 1;
function color_wheel() { function color_wheel() {
@ -529,6 +545,8 @@ function anything() {
slots[v][6] = -1; slots[v][6] = -1;
if (active_slot == v) { if (active_slot == v) {
active_slot = 0; active_slot = 0;
} else if (previous_active_slot == v) {
previous_active_slot = 0;
} }
// to_pattrstorage("getslotname", v); // to_pattrstorage("getslotname", v);
@ -538,6 +556,11 @@ function anything() {
set_active_slot(active_slot); set_active_slot(active_slot);
if (!is_dragging) { if (!is_dragging) {
outlet(0, "delete", v); outlet(0, "delete", v);
if (selected_slot == v) {
selected_slot == 0
outlet(2, 'set');
outlet(3, 'set', 0);
}
} }
trigger_writeagain(); trigger_writeagain();
} }
@ -545,8 +568,7 @@ function anything() {
} }
} }
function bang() function bang() {
{
to_pattrstorage("recall", active_slot); to_pattrstorage("recall", active_slot);
} }
@ -554,13 +576,16 @@ function msg_int(v) {
to_pattrstorage("recall", v); to_pattrstorage("recall", v);
} }
function msg_float(v) function msg_float(v) {
{
var s = Math.floor(v); var s = Math.floor(v);
var i = v % 1; var i = v % 1;
to_pattrstorage("recall", s, s+1, i); to_pattrstorage("recall", s, s+1, i);
} }
function init() {
loadbang();
}
function pattrstorage(v) { function pattrstorage(v) {
find_pattrstorage(v); find_pattrstorage(v);
paint_base(); paint_base();
@ -756,6 +781,9 @@ function lockedslots() {
if (locked_slots.length) { if (locked_slots.length) {
for (var i = 0; i < locked_slots.length; i++) { for (var i = 0; i < locked_slots.length; i++) {
slots[locked_slots[i]][5] = 1; slots[locked_slots[i]][5] = 1;
if (locked_slots[i] == selected_slot) {
select(selected_slot);
}
} }
} }
} }
@ -780,6 +808,7 @@ function read() {
} }
function resync() { function resync() {
set_active_slot(0);
calc_rows_columns(); calc_rows_columns();
} }
@ -794,6 +823,9 @@ function find_pattrstorage(name) {
to_pattrstorage("getlockedslots"); to_pattrstorage("getlockedslots");
} else { } else {
pattrstorage_name = null; pattrstorage_name = null;
active_slot = 0;
previous_active_slot = 0;
selected_slot = 0;
slots_clear(); slots_clear();
// error("Pattrstorage", name, "doesn't exist.\n"); // error("Pattrstorage", name, "doesn't exist.\n");
} }
@ -882,15 +914,22 @@ trigger_writeagain.local = 1;
// MOUSE EVENTS // MOUSE EVENTS
function onidle(x,y,but,cmd,shift,capslock,option,ctrl) function onidle(x,y,but,cmd,shift,capslock,option,ctrl)
{ {
if (last_x != x || last_y != y - y_offset|| shift_hold != shift || option_hold != option) { var redraw_flag = false;
if (last_x != x || last_y != y - y_offset) {
last_x = x; last_x = x;
last_y = y - y_offset; last_y = y - y_offset;
shift_hold = shift;
option_hold = option;
var cur = get_slot_index(x, y - y_offset); var cur = get_slot_index(x, y - y_offset);
if (cur != last_hovered) { if (cur != last_hovered) {
last_hovered = cur; last_hovered = cur;
redraw_flag = true;
}
}
if (shift_hold != shift || option_hold != option) {
shift_hold = shift;
option_hold = option;
redraw_flag = true;
} }
if (redraw_flag) {
mgraphics.redraw(); mgraphics.redraw();
} }
} }
@ -939,28 +978,6 @@ function ondblclick(x,y,but,cmd,shift,capslock,option,ctrl)
{ {
if (last_hovered > -1 && pattrstorage_name != null && filled_slots.indexOf(last_hovered) > -1) { if (last_hovered > -1 && pattrstorage_name != null && filled_slots.indexOf(last_hovered) > -1) {
to_pattrstorage("recall", last_hovered); to_pattrstorage("recall", last_hovered);
// var output = "recall";
// if (select_mode) {
// output = "select";
// }
// if (shift) {
// output = "store";
// if (option) {
// output = "delete";
// }
// } else if (slots[last_hovered][4] == null) {
// return;
// }
// if (output == "store") {
// store(last_hovered);
// } else {
// if (output == "select") {
// select(last_hovered);
// // mgraphics.redraw();
// } else {
// to_pattrstorage(output, last_hovered);
// }
// }
} }
last_x = x; last_x = x;
@ -1075,14 +1092,32 @@ function onresize(w,h)
} }
onresize.local = 1; onresize.local = 1;
// function ondblclick(x,y,but,cmd,shift,capslock,option,ctrl)
// {
// last_x = x;
// last_y = y;
// }
// ondblclick.local = 1;
// ATTRIBUTES DECLARATION // ATTRIBUTES DECLARATION
declareattribute("pattrstorage", "getpattrstorage", "setpattrstorage", 1);
function getpattrstorage() {
if (pattrstorage_name == null) {
return
} else {
return pattrstorage_name;
}
}
function setpattrstorage(v){
// This method is called for the first time when the patch is loading, before the loadbang (not all objects are instanciated yet)
// With v being the value stored whithin the patcher
if (v == null) {
pattrstorage_name = null;
pattrstorage_obj = null;
} else {
pattrstorage_name = arrayfromargs(arguments)[0];
}
// If the loadbang already occured once, we need to retrigger here
if (has_loaded) {
find_pattrstorage(pattrstorage_name);
loadbang();
}
// Otherwise, we just wait for the patch to call loadbang automatically at the end of its startup routine.
}
declareattribute("bubblesize", "getslotsize", "setslotsize", 1); declareattribute("bubblesize", "getslotsize", "setslotsize", 1);
function getslotsize() { function getslotsize() {
return slot_size; return slot_size;
@ -1467,3 +1502,10 @@ function setcolor6(){
error('color_6: wrong number of arguments\n'); error('color_6: wrong number of arguments\n');
} }
} }
// UTILITY
function post_keys(obj) {
post('Keys of obj: ', obj, '\n');
post(Object.keys(obj));
post('\n');
}

83
tc.preset_demo.maxpat

@ -4,13 +4,13 @@
"appversion" : { "appversion" : {
"major" : 8, "major" : 8,
"minor" : 6, "minor" : 6,
"revision" : 2, "revision" : 3,
"architecture" : "x64", "architecture" : "x64",
"modernui" : 1 "modernui" : 1
} }
, ,
"classnamespace" : "box", "classnamespace" : "box",
"rect" : [ 34.0, 100.0, 854.0, 848.0 ], "rect" : [ 310.0, 100.0, 854.0, 848.0 ],
"bglocked" : 0, "bglocked" : 0,
"openinpresentation" : 0, "openinpresentation" : 0,
"default_fontsize" : 12.0, "default_fontsize" : 12.0,
@ -39,6 +39,42 @@
"subpatcher_template" : "", "subpatcher_template" : "",
"assistshowspatchername" : 0, "assistshowspatchername" : 0,
"boxes" : [ { "boxes" : [ {
"box" : {
"id" : "obj-31",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 245.5, 565.0, 89.0, 22.0 ],
"text" : "storagewindow"
}
}
, {
"box" : {
"id" : "obj-25",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 422.0, 598.0, 45.0, 22.0 ],
"text" : "store 3"
}
}
, {
"box" : {
"id" : "obj-14",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 360.5, 586.0, 29.5, 22.0 ],
"text" : "init"
}
}
, {
"box" : { "box" : {
"id" : "obj-128", "id" : "obj-128",
"items" : [ "Grid", ",", "List" ], "items" : [ "Grid", ",", "List" ],
@ -69,7 +105,7 @@
"maxclass" : "comment", "maxclass" : "comment",
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 0, "numoutlets" : 0,
"patching_rect" : [ 959.0, 908.0, 131.0, 33.0 ], "patching_rect" : [ 959.0, 908.0, 133.0, 33.0 ],
"text" : "Set a given color (from 1 to 6)" "text" : "Set a given color (from 1 to 6)"
} }
@ -82,7 +118,6 @@
"numoutlets" : 1, "numoutlets" : 1,
"outlettype" : [ "" ], "outlettype" : [ "" ],
"patching_rect" : [ 830.0, 927.0, 123.0, 22.0 ], "patching_rect" : [ 830.0, 927.0, 123.0, 22.0 ],
"presentation_linecount" : 2,
"text" : "color_wheel 3 0 1 1 1" "text" : "color_wheel 3 0 1 1 1"
} }
@ -129,7 +164,7 @@
"maxclass" : "comment", "maxclass" : "comment",
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 0, "numoutlets" : 0,
"patching_rect" : [ 928.0, 780.0, 150.0, 87.0 ], "patching_rect" : [ 928.0, 780.0, 151.0, 87.0 ],
"text" : "When color mode is set to cycle, stored presets are shown in colors from color_1 to color_6, cyclically depending on their slot number." "text" : "When color mode is set to cycle, stored presets are shown in colors from color_1 to color_6, cyclically depending on their slot number."
} }
@ -303,7 +338,7 @@
"appversion" : { "appversion" : {
"major" : 8, "major" : 8,
"minor" : 6, "minor" : 6,
"revision" : 2, "revision" : 3,
"architecture" : "x64", "architecture" : "x64",
"modernui" : 1 "modernui" : 1
} }
@ -967,7 +1002,7 @@
, { , {
"box" : { "box" : {
"id" : "obj-8", "id" : "obj-8",
"items" : [ "0 (tmp)", ",", "1 <(unnamed)>", ",", "2 <(unnamed)>", ",", "3 <(unnamed)>", ",", "4 <(unnamed)>", ",", "5 <(unnamed)>", ",", "6 <(unnamed)>", ",", "7 onze", ",", "8 up", ",", "9 <(unnamed)>", ",", "10 oui", ",", "11 <(unnamed)>", ",", "12 <(unnamed)>", ",", "13 <(unnamed)>", ",", "14 <(unnamed)>", ",", "15 <(unnamed)>" ], "items" : [ "6 <(unnamed)>", ",", "19 <(unnamed)>", ",", "39 <(unnamed)>" ],
"maxclass" : "umenu", "maxclass" : "umenu",
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 3, "numoutlets" : 3,
@ -987,7 +1022,7 @@
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 0, "numoutlets" : 0,
"patching_rect" : [ 72.0, 139.0, 507.0, 87.0 ], "patching_rect" : [ 72.0, 139.0, 507.0, 87.0 ],
"text" : "Pattrstorage messages that doesn't trigger output and need to be sent to the jsui instead:\n- store (send to jsui only)\n- recallmulti (send to pattrstorage first for timing accuracy, then to jsui)\n- slotname (send \"setslotname\" or \"text\" to jsui instead, will rename active slot)\n- lock (or setlock to lock/unlock of the active slot)\n- some other. I've not tested them all. " "text" : "Pattrstorage messages that doesn't trigger output and need to be sent to the jsui instead:\n- store (send to jsui only)\n- recallmulti (send to pattrstorage first for timing accuracy, then to jsui)\n- slotname (send \"setslotname\" or \"text\" to jsui instead, will rename selected slot)\n- lock (or setlock to lock/unlock of the active slot)\n- some other. I've not tested them all. "
} }
} }
@ -1056,18 +1091,17 @@
, { , {
"box" : { "box" : {
"border" : 0, "border" : 0,
"embedstate" : [ [ "autowriteagain", 0 ], [ "active_slot_color", 0.808, 0.898, 0.91, 1 ], [ "color_4", 0.367, 0.542, 0.712, 1 ], [ "slot_round", 0 ], [ "stored_slot_color", 0.502, 0.502, 0.502, 1 ], [ "layout", 0 ], [ "select_mode", 0 ], [ "color_5", 0.283, 0.606, 0.559, 1 ], [ "text_color", 0.129, 0.129, 0.129, 1 ], [ "color_mode", 0 ], [ "color_1", 0.743, 0.41, 0.501, 1 ], [ "bubblesize", 20 ], [ "interp_slot_color", 1, 1, 1, 0.8 ], [ "margin", 4 ], [ "color_6", 0.316, 0.616, 0.377, 1 ], [ "fontsize", 14 ], [ "scrollable", 1 ], [ "empty_slot_color", 0.349, 0.349, 0.349, 1 ], [ "color_2", 0.679, 0.405, 0.669, 1 ], [ "fontname", "Arial" ], [ "ignoreslotzero", 1 ], [ "spacing", 4 ], [ "text_bg_color", 1, 1, 1, 0.5 ], [ "min_rows", 50 ], [ "bgcolor", 0.2, 0.2, 0.2, 1 ], [ "color_3", 0.527, 0.459, 0.756, 1 ], [ "displayinterp", 1 ] ], "embedstate" : [ [ "layout", 0 ], [ "color_6", 0.316, 0.616, 0.377, 1 ], [ "text_color", 0.129, 0.129, 0.129, 1 ], [ "ignoreslotzero", 1 ], [ "min_rows", 50 ], [ "bgcolor", 0.2, 0.2, 0.2, 1 ], [ "spacing", 4 ], [ "empty_slot_color", 0.349, 0.349, 0.349, 1 ], [ "displayinterp", 1 ], [ "color_1", 0.743, 0.41, 0.501, 1 ], [ "text_bg_color", 1, 1, 1, 0.5 ], [ "slot_round", 0 ], [ "color_2", 0.679, 0.405, 0.669, 1 ], [ "color_4", 0.367, 0.542, 0.712, 1 ], [ "autowriteagain", 0 ], [ "color_3", 0.527, 0.459, 0.756, 1 ], [ "active_slot_color", 0.808, 0.898, 0.91, 1 ], [ "color_mode", 0 ], [ "margin", 4 ], [ "interp_slot_color", 1, 1, 1, 0.8 ], [ "fontsize", 14 ], [ "select_mode", 0 ], [ "color_5", 0.283, 0.606, 0.559, 1 ], [ "bubblesize", 20 ], [ "stored_slot_color", 0.502, 0.502, 0.502, 1 ], [ "scrollable", 1 ], [ "fontname", "Arial" ], [ "pattrstorage", "test" ] ],
"filename" : "tc.preset.js", "filename" : "tc.preset.js",
"id" : "obj-10", "id" : "obj-10",
"jsarguments" : [ "test" ],
"maxclass" : "jsui", "maxclass" : "jsui",
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 4, "numoutlets" : 4,
"outlettype" : [ "", "", "", "" ], "outlettype" : [ "", "", "", "" ],
"parameter_enable" : 0, "parameter_enable" : 0,
"patching_rect" : [ 72.0, 637.0, 364.0, 124.0 ], "patching_rect" : [ 72.0, 636.0, 364.0, 125.0 ],
"presentation" : 1, "presentation" : 1,
"presentation_rect" : [ 1.0, 103.0, 269.0, 77.0 ] "presentation_rect" : [ 1.0, 103.0, 293.0, 149.0 ]
} }
} }
@ -1125,10 +1159,10 @@
"outlettype" : [ "" ], "outlettype" : [ "" ],
"patching_rect" : [ 72.0, 599.0, 176.0, 22.0 ], "patching_rect" : [ 72.0, 599.0, 176.0, 22.0 ],
"saved_object_attributes" : { "saved_object_attributes" : {
"client_rect" : [ 27, 158, 514, 944 ], "client_rect" : [ 1450, 76, 2131, 1323 ],
"parameter_enable" : 0, "parameter_enable" : 0,
"parameter_mappable" : 0, "parameter_mappable" : 0,
"storage_rect" : [ 25, 107, 816, 991 ] "storage_rect" : [ 583, 69, 1034, 197 ]
} }
, ,
"text" : "pattrstorage test @savemode 0", "text" : "pattrstorage test @savemode 0",
@ -1334,6 +1368,13 @@
"source" : [ "obj-131", 0 ] "source" : [ "obj-131", 0 ]
} }
}
, {
"patchline" : {
"destination" : [ "obj-10", 0 ],
"source" : [ "obj-14", 0 ]
}
} }
, { , {
"patchline" : { "patchline" : {
@ -1387,6 +1428,13 @@
"source" : [ "obj-24", 0 ] "source" : [ "obj-24", 0 ]
} }
}
, {
"patchline" : {
"destination" : [ "obj-10", 0 ],
"source" : [ "obj-25", 0 ]
}
} }
, { , {
"patchline" : { "patchline" : {
@ -1408,6 +1456,13 @@
"source" : [ "obj-3", 1 ] "source" : [ "obj-3", 1 ]
} }
}
, {
"patchline" : {
"destination" : [ "obj-1", 0 ],
"source" : [ "obj-31", 0 ]
}
} }
, { , {
"patchline" : { "patchline" : {

Loading…
Cancel
Save