Compare commits

..

3 Commits

  1. 4
      README.md
  2. 38
      code/tc.preset.js
  3. 91
      docs/tc.preset.maxref.xml
  4. 5
      extra/tc.preset_demo.maxpat
  5. 1560
      help/tc.preset.maxhelp
  6. 65
      help/test.json
  7. 2
      init/tc.preset_init.txt
  8. 28
      package-info.json
  9. 523
      snippets/tc.preset all-in-one.maxsnip

4
README.md

@ -32,15 +32,13 @@ A [jsui] replacement for the [preset] object in Cycling'74 Max.
- `recall`: 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 (`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, if ever) ## Desired features (for someday, if ever)
- 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
- Accept more pattrstorage messages: (`clear`, `insert`, `lockall`, `read`, `readagain`, `remove`, `renumber`), and act as a passthrough for the ones that don't affect the presets.
- Authoring (make a Max package out of this and create `maxref.xml` files)
## Known bugs ## Known bugs
- With slot_round > 0, interpolation visualization is a bit wacky - With slot_round > 0, interpolation visualization is a bit wacky

38
tc.preset.js → code/tc.preset.js

@ -37,7 +37,7 @@ mgraphics.relative_coords = 0;
mgraphics.autofill = 0; mgraphics.autofill = 0;
// LOOK // LOOK
var slot_size = 20; var slot_size = 14;
var slot_round = 0; var slot_round = 0;
var slot_round_ratio = 0; var slot_round_ratio = 0;
@ -108,6 +108,12 @@ var drag_slot = -1; // Stores the slot that's being dragged
var has_loaded = false; var has_loaded = false;
// RESIZING
// 64x64 is the default jsui size. We use that to know if the object has just been created,
// in which case we resize it to a more convenient size to start with.
if (ui_width == 64 && ui_height == 64) {
box.setboxattr("patching_rect", box.rect[0], box.rect[1], 130, 58);
}
// Allows for dynamic resizing even in presentation mode (addressing the limitation of onresize()) // Allows for dynamic resizing even in presentation mode (addressing the limitation of onresize())
var pres_rect = new MaxobjListener(this.box,"presentation_rect",get_prect); var pres_rect = new MaxobjListener(this.box,"presentation_rect",get_prect);
function get_prect(prect) { function get_prect(prect) {
@ -118,9 +124,9 @@ if (jsarguments.length>1) { // Depreciated, use "pattrstorage" attribute instead
pattrstorage_name = jsarguments[1]; pattrstorage_name = jsarguments[1];
} }
// FUNCTIONS
function loadbang() { function loadbang() {
has_loaded = true; 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();
@ -313,13 +319,12 @@ paint_base.local = 1;
function paint() function paint()
{ {
// post("redraw\n");
// Handling Presentation mode enable/disable // Handling Presentation mode enable/disable
var cur_size = mgraphics.size; var cur_size = mgraphics.size;
if (cur_size[0] != ui_width || cur_size[1] != ui_height) { if (cur_size[0] != ui_width || cur_size[1] != ui_height) {
onresize(cur_size[0], cur_size[1]); onresize(cur_size[0], cur_size[1]);
} else { } else {
// post("redraw\n");
with (mgraphics) { with (mgraphics) {
select_font_face(font_name); select_font_face(font_name);
set_font_size(font_size); set_font_size(font_size);
@ -565,6 +570,17 @@ function anything() {
trigger_writeagain(); trigger_writeagain();
} }
} }
} else {
// Passthrough to pattrstorage
var args = arrayfromargs(arguments);
args.unshift(messagename);
to_pattrstorage.apply(null, args);
// If the called function messes with presets, we resync the jsui
var mess_with_presets = ['insert', 'lockall', 'read', 'readagain', 'remove', 'renumber'];
if (mess_with_presets.indexOf(messagename) > -1 ) {
resync();
}
} }
} }
@ -809,7 +825,11 @@ function read() {
function resync() { function resync() {
set_active_slot(0); set_active_slot(0);
slots_clear();
to_pattrstorage("getslotlist");
to_pattrstorage("getlockedslots");
calc_rows_columns(); calc_rows_columns();
} }
function find_pattrstorage(name) { function find_pattrstorage(name) {
@ -893,11 +913,12 @@ function update_umenu() {
outlet(1, "clear"); outlet(1, "clear");
for (var i=0; i < filled_slots.length; i++) { for (var i=0; i < filled_slots.length; i++) {
var txt = filled_slots[i].toString(); var nb = filled_slots[i];
var txt = null;
if (!menu_number_only) { if (!menu_number_only) {
txt += ' ' + slots[filled_slots[i]][4]; txt = slots[filled_slots[i]][4];
} }
outlet(1, "append", txt); outlet(1, "append", nb, txt);
} }
} }
} }
@ -1086,7 +1107,6 @@ function onresize(w,h)
ui_width = w; ui_width = w;
ui_height = h; ui_height = h;
calc_rows_columns(); calc_rows_columns();
// loadbang();
to_pattrstorage("getslotlist"); to_pattrstorage("getslotlist");
paint_base(); paint_base();
} }
@ -1339,7 +1359,7 @@ function setignoreslotzero(v){
} }
} }
declareattribute("displayinterp", "getdisplayinterp", "setdisplayinterp", 1); declareattribute("display_interp", "getdisplayinterp", "setdisplayinterp", 1);
function getdisplayinterp() { function getdisplayinterp() {
return display_interp; return display_interp;
} }

91
docs/tc.preset.maxref.xml

@ -7,7 +7,7 @@
</digest> </digest>
<description> <description>
tc.preset is a jsui clone of the preset object, but loaded with more features, such as preset organization through drag and drop, display as a scrollable list, auto-rewrite the saved JSON/XML file after any change. tc.preset is a jsui clone of the preset object, but loaded with more features, such as preset organization through drag and drop, display as a scrollable list, auto-rewrite the saved JSON/XML file after any change.
Contrary to the preset object, tc.preset has to be used in conjonction with a pattrstorage object.<modification class=""></modification> Contrary to the preset object, tc.preset doesn't work alone and has to be used in conjonction with a pattrstorage object.<modification class=""></modification>
</description> </description>
@ -52,6 +52,13 @@
<digest>Function depends on inlet</digest> <digest>Function depends on inlet</digest>
<description>Function depends on inlet</description> <description>Function depends on inlet</description>
</method> --> </method> -->
<method name="color_wheel">
<digest>Set the slot colors</digest>
<description>The message "color_wheel", followed by an integer and four float, defines one of the 6 available slot colors when color_mode is enabled.
The integer argument, between 1 and 6, defines which color in being modifier, and next the four floats define the color in the RGBA format.
The message "color_wheel" without argument resets the six colors to their default values.
</description>
</method>
<method name="pattrstorage"> <method name="pattrstorage">
<digest>Link to named pattrstorage object</digest> <digest>Link to named pattrstorage object</digest>
<description>The word 'pattrstorage' followed by the name of an existing pattrstorage links the jsui to that pattrstorage. <description>The word 'pattrstorage' followed by the name of an existing pattrstorage links the jsui to that pattrstorage.
@ -81,6 +88,7 @@
<description>Same as setslotname. Allows to connect the leftmost outlet of a textedit to the jsui and use it as an interface to rename the selected presets. <description>Same as setslotname. Allows to connect the leftmost outlet of a textedit to the jsui and use it as an interface to rename the selected presets.
</description> </description>
</method> </method>
</methodlist> </methodlist>
@ -95,11 +103,90 @@
<digest>Automatic writeagain</digest> <digest>Automatic writeagain</digest>
<description>When set to 1, the jsui will automatically send a "writeagain" message to its linked pattrstorage anytime a preset have been stored, moved, renamed, (un)locked or deleted, saving any change into the preset file immediately.</description> <description>When set to 1, the jsui will automatically send a "writeagain" message to its linked pattrstorage anytime a preset have been stored, moved, renamed, (un)locked or deleted, saving any change into the preset file immediately.</description>
</attribute> </attribute>
<attribute name='bgcolor' get='1' set='1' type='list' size='4' >
<digest>Background color</digest>
<description>Sets the background color of the object in RGBA format</description>
</attribute>
<attribute name='bubblesize' get='1' set='1' type='float' size='1' > <attribute name='bubblesize' get='1' set='1' type='float' size='1' >
<digest>Slot size</digest> <digest>Slot size</digest>
<description>Size of the preset slots</description> <description>Size of the preset slots</description>
</attribute> </attribute>
<attribute name='color_mode' get='1' set='1' type='int' size='1' >
<digest>Color mode</digest>
<description>When set to 0, all preset slots have the same color (same as the preset object). When set to 1, stored preset slots are colored. See color_1 to color_6 as well as the color_wheel message.</description>
</attribute>
<attribute name='color_1' get='1' set='1' type='list' size='4' >
<digest>Slot color 1</digest>
<description>Slot color 1 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='color_2' get='1' set='1' type='list' size='4' >
<digest>Slot color 2</digest>
<description>Slot color 2 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='color_3' get='1' set='1' type='list' size='4' >
<digest>Slot color 3</digest>
<description>Slot color 3 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='color_4' get='1' set='1' type='list' size='4' >
<digest>Slot color 4</digest>
<description>Slot color 4 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='color_5' get='1' set='1' type='list' size='4' >
<digest>Slot color 5</digest>
<description>Slot color 5 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='color_6' get='1' set='1' type='list' size='4' >
<digest>Slot color 6</digest>
<description>Slot color 6 in RGBA format. Sending this message without arguments resets the color to its default value. Has an effect only when color_mode is enabled.</description>
</attribute>
<attribute name='display_interp' get='1' set='1' type='int' size='1' >
<digest>Display interpolation</digest>
<description>When set to 1, the jsui will display the ongoing interpolation between presets when a recall message with three arguments or a recallmulti message with at least one argument are sent to the linked pattrstorage.
Notice that the recallmutli message needs to be sent both the pattrstorage and the jsui.</description>
</attribute>
<attribute name='empty_slot_color' get='1' set='1' type='list' size='4' >
<digest>Empty slot color</digest>
<description>Sets the empty slot color of the object in RGBA format</description>
</attribute>
<attribute name='layout' get='1' set='1' type='int' size='1' >
<digest>How presets are displayed</digest>
<description>When set to 0, the jsui mimics the default preset object: slots are displayed in a grid. When set to 1, they are displayed as a vertical list, with the preset slots on the left and their name on the right.</description>
</attribute>
<attribute name='margin' get='1' set='1' type='float' size='1' >
<digest>Object margin</digest>
<description>Defines the size, in pixels, of the margin between the jsui border and the preset slots.</description>
</attribute>
<attribute name='min_rows' get='1' set='1' type='int' size='1' >
<digest>Minimum number of rows to display</digest>
<description>Defines the minimum number of rows to display if scrollable is enabled and layout is set to 1.
If a preset is stored in a slot with a higher value than min_row, then min_row is ignored and presets are displayed up to the highest stored one.
</description>
</attribute>
<attribute name='scrollable' get='1' set='1' type='int' size='1' >
<digest>Scroll through your presets</digest>
<description>When set to 1, you can through the jsui to see all your presets, or at least up to the slot number defined by the min_rows attributes. Currently only works with the list layout.
</description>
</attribute>
<attribute name='select_mode' get='1' set='1' type='int' size='1' >
<digest>Preset selection mode</digest>
<description>When set to 1, a single click on a stored preset selects it without recalling it. It allows to drag it, set its name and lock state while keeping the last recalled preset active.
You need to double-click on a stored preset to recall it. If set to 0, stored presets are recalled by a single click (default preset object behavior).
</description>
</attribute>
<attribute name='slot_round' get='1' set='1' type='float' size='1' >
<digest>Slot corner rounding</digest>
<description>Defines the rounding of the slots corners. A value of zero means square corners. A value equal or superior to half the bubblesize makes the slots as a circle.
</description>
</attribute>
<attribute name='spacing' get='1' set='1' type='float' size='1' >
<digest>Slot spacing</digest>
<description>Defines the spacing, in pixels, between slot bubbles.
</description>
</attribute>
<attribute name='stored_slot_color' get='1' set='1' type='list' size='4' >
<digest>Stored slot color</digest>
<description>Sets the stored preset color of the object in RGBA format</description>
</attribute>
</attributelist> </attributelist>

5
tc.preset_demo.maxpat → extra/tc.preset_demo.maxpat

@ -994,15 +994,14 @@
"parameter_enable" : 0, "parameter_enable" : 0,
"patching_rect" : [ 302.0, 772.0, 100.0, 50.0 ], "patching_rect" : [ 302.0, 772.0, 100.0, 50.0 ],
"presentation" : 1, "presentation" : 1,
"presentation_rect" : [ 146.0, 63.5, 119.0, 22.0 ], "presentation_rect" : [ 146.0, 63.5, 119.0, 22.0 ]
"text" : "<(unnamed)>"
} }
} }
, { , {
"box" : { "box" : {
"id" : "obj-8", "id" : "obj-8",
"items" : [ "6 <(unnamed)>", ",", "19 <(unnamed)>", ",", "39 <(unnamed)>" ], "items" : "<empty>",
"maxclass" : "umenu", "maxclass" : "umenu",
"numinlets" : 1, "numinlets" : 1,
"numoutlets" : 3, "numoutlets" : 3,

1560
tc.preset.maxhelp → help/tc.preset.maxhelp

File diff suppressed because it is too large Load Diff

65
help/test.json

@ -0,0 +1,65 @@
{
"pattrstorage" : {
"name" : "test",
"slots" : {
"1" : {
"id" : 1,
"name" : "up",
"data" : {
"u099005226" : [ -0.714285714285714, -0.714285714285714, -0.6, -0.542857142857143, -0.457142857142857, -0.342857142857143, -0.171428571428571, -0.028571428571429, 0.028571428571428, 0.142857142857143, 0.228571428571429, 0.371428571428571, 0.485714285714286, 0.571428571428571, 0.714285714285714, 0.8 ],
"slot colors::colors" : [ 65 ],
"appearance::test" : [ -1 ],
"snippet::mypat" : [ -1 ],
"behavior::test" : [ -1 ],
"messages::test" : [ -1 ]
}
}
,
"2" : {
"id" : 2,
"name" : "down",
"data" : {
"u099005226" : [ 0.873015873015873, 0.714285714285714, 0.587301587301587, 0.46031746031746, 0.301587301587302, 0.174603174603175, 0.015873015873016, -0.111111111111111, -0.238095238095238, -0.333333333333333, -0.428571428571429, -0.523809523809524, -0.587301587301587, -0.682539682539683, -0.777777777777778, -0.873015873015873 ],
"slot colors::colors" : [ 65 ],
"appearance::test" : [ -1 ],
"snippet::mypat" : [ -1 ],
"behavior::test" : [ -1 ],
"messages::test" : [ -1 ]
}
}
,
"3" : {
"id" : 3,
"name" : "sine",
"data" : {
"u099005226" : [ -0.079365079365079, 0.206349206349206, 0.428571428571429, 0.682539682539683, 0.904761904761905, 0.904761904761905, 0.841269841269841, 0.555555555555556, 0.047619047619048, -0.301587301587302, -0.587301587301587, -0.682539682539683, -0.650793650793651, -0.428571428571429, -0.111111111111111, 0.079365079365079 ],
"slot colors::colors" : [ 65 ],
"appearance::test" : [ -1 ],
"snippet::mypat" : [ -1 ],
"behavior::test" : [ -1 ],
"messages::test" : [ -1 ]
}
}
,
"4" : {
"id" : 4,
"name" : "random",
"data" : {
"u099005226" : [ -0.587301587301587, 0.365079365079365, -0.46031746031746, -0.015873015873016, 0.904761904761905, -0.714285714285714, 0.206349206349206, -0.142857142857143, 0.428571428571429, -0.746031746031746, 0.587301587301587, -0.619047619047619, -0.047619047619048, -0.555555555555556, -0.428571428571429, 0.396825396825397 ],
"slot colors::colors" : [ 65 ],
"appearance::test" : [ -1 ],
"snippet::mypat" : [ -1 ],
"behavior::test" : [ -1 ],
"messages::test" : [ -1 ]
}
}
}
}
}

2
init/tc.preset_init.txt

@ -0,0 +1,2 @@
max objectfile tc.preset tc.preset;
max definesubstitution tc.preset jsui @filename tc.preset

28
package-info.json

@ -0,0 +1,28 @@
{
"name" : "tc.preset",
"displayname" : "",
"version" : "0.0.1",
"author" : "Théophile Clet",
"authors" : [ ],
"description" : "A jsui replacement for the preset object",
"tags" : ["preset", "pattrstorage", "jsui"],
"website" : "",
"extends" : "",
"extensible" : 0,
"max_version_min" : "8.6.2",
"max_version_max" : "none",
"os" : {
"macintosh" : {
"min_version" : "10.11.x",
"platform" : [ "x64", "aarch64" ]
}
,
"windows" : {
"min_version" : "10",
"platform" : [ "x64" ]
}
}
,
"homepatcher" : "tc.preset_demo.maxpat"
}

523
snippets/tc.preset all-in-one.maxsnip

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save