diff --git a/README.build b/README.build index 26b00e6..a83802c 100644 --- a/README.build +++ b/README.build @@ -1,22 +1,23 @@ -BUILDING AND INSTALLING MFP +BUILDING AND INSTALLING MFP =================================== -Post version 0.06, 2016-02-07 +Post version 0.07, 2024-01-15 TL;DR --------------------- - $ ./waf configure --python=python3 --virtualenv --prefix ~/mfpvirt build install install_deps - [...] - $ . ~/mfpvirt/bin/activate - (mfpvirt)$ mfp -v + $ ./waf configure --python=python3 --virtualenv --prefix ~/mfpvirt build install install_deps + [...] + $ . ~/mfpvirt/bin/activate + (mfpvirt)$ mfp -v -THINGS TO KNOW +THINGS TO KNOW --------------------- -OS platform: I have only tested MFP on 64-bit Linux. +OS platform: I have only tested MFP on 32-bit (raspi) and 64-bit +Linux. -python: MFP requires Python 3.x at this time. +python: MFP requires Python 3.x at this time. waf: MFP uses 'waf', which you can think of as a replacement for autotools and make. You do not need to install waf; the correct @@ -25,7 +26,7 @@ is designed to work; more information can be found at https://code.google.com/p/waf/. MFP's "Makefile" or "configure.in" equivalent is the file "wscript", which is a plain Python file. The entry points used by waf are the functions -"configure" and "build", defined near the bottom of the file. +"configure" and "build", defined near the bottom of the file. virtualenv: At this phase of MFP's development you should probably build it in a "virtualenv" sandbox. The waf scripts @@ -35,112 +36,143 @@ configure with --virtualenv as in the TL;DR above and the build will go into the virtual environment. When you specify --virtualenv, the install prefix (--prefix) is the path to the virtual environment, so you shouldn't let this default to -/usr/local. +/usr/local. setuptools: The build process depends on Python setuptools. If you have virtualenv installed, you have setuptools already, but if you aren't using virtualenv you may need to install setuptools separately. It's packaged as "python-setuptools" on Debian and -Ubuntu. +Ubuntu. pip: The modern replacement for "easy_install" to install Python packages is called pip. If (1) you are using Debian or Ubuntu, (2) you do not want to use a --virtualenv install, and (3) you want to use the './waf install_deps' feature to install some Python dependencies, you need the Debian package 'python-pip', or your distro's equivalent, -installed. +installed. gcc: The C components of mfp (mfpdsp, pluginfo, and testext) are straightforward C but include some c99-isms, mainly due to LV2. I have been using versions from gcc-4.8.3 to 9.3.0 with no trouble. -CONFIGURING +CONFIGURING ----------------------- -The basic form: +The basic form: - $ ./waf configure [options] + $ ./waf configure [options] A full list of options is shown by ./waf --help, under "Configuration options". --virtualenv is the only "custom" -option. +option. LIBRARIES ----------------------- The "mfpdsp" C library/program needs a few C libraries with their -development headers and pkg-config files installed: - +development headers and pkg-config files installed: + * ladspa.h (LADSPA plugins) - * glib-2.0 (GLib/GObject) + * glib-2.0 (GLib/GObject) * json-glib-2.0 (JSON serializing/deserializing) - * serd-0 (LV2 TTL parsing) + * serd-0 (LV2 TTL parsing) * jack (duh) * liblo (OSC library, needed by pyliblo) * lv2 headers (LV2 load/save) -You'll get errors in the "./waf configure" process if these aren't installed. +You'll get errors in the "./waf configure" process if these aren't installed. Python runtime dependencies are checked for in "configure" and many of them can be automagically installed by "./waf install_deps" if you -wish. +wish. install_deps must be run after "./waf install". If you are using a virtualenv, the installed Python libraries will also -be installed into the virtualenv. +be installed into the virtualenv. Note that the Python language bindings for Gtk+/GLib and Clutter libraries CANNOT be automatically installed by this build process. You need to install your OS package manager's package for the "GIR" (GObject Introspection Repository) data for Clutter, Glib, Gtk+, Gdk, GtkClutter, and Pango, and the Python infrastructure to use that data. -In Debian, these are packaged as: +In Debian, these are packaged as: gir1.2-clutter-1.0 - gir1.2-gtkclutter-1.0 + gir1.2-gtkclutter-1.0 gir1.2-pango-1.0 gir1.2-glib-2.0 - gir1.2-gtk-3.0 - python-gi + gir1.2-gtk-3.0 + python-gi -BUILDING +BUILDING ----------------------- - $ ./waf build + $ ./waf build This will build the project into ./wafbuild (or other directory as specified to "configure"). There may be some temporary stuff placed into ./build/ and ./dist/ by setuptools, so I wouldn't use those as -names for the waf build directory. +names for the waf build directory. INSTALLING -------------------------- - $ ./waf install + $ ./waf install The installation root defaults to /usr/local and can be modified by passing in the --prefix argument to "./waf configure". -If you get errors on the install step to the effect of os.symlink -failing to make a link because the file already exists -- see GitHub +If you get errors on the install step to the effect of os.symlink +failing to make a link because the file already exists -- see GitHub issue #220 and please add a comment indicating your Linux distribution -and that you are having this problem. +and that you are having this problem. Note that the instances of #220 I have seen are failing at the very tail end of the install process, and are trying to install files that are already there... which means that you can probably ignore this error. Try activating the virtualenv and running -mfp. If it launches, you are good to go. +mfp. If it launches, you are good to go. + + +DESKTOP FILE +-------------------------- + +The template desktop file `mfp.desktop` will be populated with +paths and installed to ${PREFIX}/share/mfp/mfp.desktop. You will +need to copy it to wherever such things go on your system. + +The icon path is what I needed to get icons working on my Gnome +system. You may need to change it. If you need to do something +manual, the actual icon image is the one in mfp.svg. I can't +express how crabby I am about how messed up icons are on the +Linux desktop. + +For what it's worth, on my system the desktop file should be +~/.local/share/applications/mfp.desktop + RUNNING TESTS -------------------------- There are some tests, though not as many as I would like. What's there basically comes in two flavors, all of which can be run -with various incantations of the `nosetests` test runner: +with various incantations of the `nosetests` test runner: - * Python test cases in mfp/test: run with plain `python /usr/bin/nosetests -v mfp/` + * Python test cases in mfp/test: run with plain `nosetests -v mfp/test/` * C test cases in mfpdsp/test_*: run with the `testext` plugin - to nosetests, `python /usr/bin/nosetests -v --with-testext --exe wafbuild/libmfpdsp.so` + to nosetests, `nosetests -v --with-testext --exe wafbuild/libmfpdsp.so` + +Note on nosetests: I started using it because, 12+ years ago, it +was the best test runner. Now other tools like pytest have won +more mindshare. I spent some effort on the plugins to run C tests +for mfpdsp so I am sticking with nosetests. + +HOWEVER, the original nosetests is abandoned and doesn't work +with current Python versions, and the "new" version of nosetests +(nose2) changed the way plugins worked, and doesn't support the +--exe option needed to point nose to the libmfpdsp.so file. So I +switched over to "pynose", which is a fork of the original +nosetests, just updated to work with contemporary Python. It gets +installed by install_deps. diff --git a/README.md b/README.md index 3b99b3c..c95a000 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Up next: * Refactor UI actions to support undo/redo * Loading audio files into [buffer~] * Named presets for patches -* Port to GTK4, making UI improvements along the way +* Port to Dear ImGUI, making UI improvements along the way * Self-contained save format including sample and image files ### BUILDING @@ -72,13 +72,16 @@ object, including assigned MIDI and OSC controllers. ## KNOWN BROKEN There are a number of bugs that I hoped to get fixed by this -release (0.05) but have not. Here are some that I will just have +release (0.7) but have not. Here are some that I will just have to ask for your patience with: Ticket | Description -------| -------------- - #165 | Markup in comments does not render when patch is loaded. Workaround: Click in another window. - #217 | MFP must be stopped with `kill -9` in (hopefully rare) error conditions. Workaround: ^Z to stop the process from the shell, then `kill -9 %1` + #299 | If JACK isn't running and can't be started, launch fails ugly + #298 | Occasional retry loop on quit + #297 | Bad behavior on abort of file load + #292 | In larger patches, selection and interaction may get messed up + #291 | When editing a label, the cursor disappears #204 | Logging is broken when loaded as LV2 plugin #212 | Rendering of smooth curves on XY plot shows gaps #220 | 'waf install' can give error messages. Workaround: See the bottom of README.build; possibly no action is required. diff --git a/doc/ANNOUNCE-0.07.txt b/doc/ANNOUNCE-0.07.txt new file mode 100644 index 0000000..7fa8072 --- /dev/null +++ b/doc/ANNOUNCE-0.07.txt @@ -0,0 +1,123 @@ +MFP -- Music For Programmers +Release 0.7 + +I'm pleased to announce a new version of MFP, mostly consisting +of internal refactoring and architecture changes. It's been +almost 7 years since the last release! This one may not have a lot +of user-facing changes, but MFP is much improved internally and this +release is the base for what I hope will be a lot of exciting future +work. + +If you're wondering why it's been so long since the last release, +the TL;DR is J-O-B. Recently I have managed to find a time slot +to work on my personal projects more and I've been really +enjoying getting back into MFP development. + +A summary of changes is below. Please see the GitHub issue tracker +for complete details: + + http://github.com/bgribble/mfp + +This version is still source-code-only, but the new build system +should make it a bit easier for those who would like to try it. + +Significant changes since release v0.06 +---------------------------------------- + +* Internal architecture converted to use Python asyncio rather than + threads. + +* RPC between main process, DSP process, and UI process shifted + to a separately-released package called "carp" (will be installed + as part of build process) + +* RPC serialization mostly uses protobuf for efficiency + +* UI code refactored into toolkit-agnostic and toolkit-dependent + code, in anticipation of beginning a migration to Dear ImGUI + +* Built UI state management out with a separately-released + package called "flopsy" (will be installed as part of build + process). This is building the foundation for robust undo/redo, + but still not there yet. + +* Added a step debugger with breakpoints for debugging patches + +* Lots of new builtins and bugfixes resulting from my attempts to +do the 2023 and 2024 Advent of Code in MFP patches. + + +About MFP +---------------------------------------- + +MFP is an environment for visually composing computer programs, +with an emphasis on music and real-time audio synthesis and +analysis. It's very much inspired by Miller Puckette's Pure Data +(pd) and Max/MSP, with a bit of LabView and TouchOSC for good +measure. It is targeted at musicians, recording engineers, and +software developers who like the "patching" dataflow metaphor for +coding up audio synthesis, processing, and analysis. + +MFP is a completely new code base, written in Python and C, with +a Clutter UI. It has been under development by a solo developer +(me!), as a spare-time project for several years. + +Compared to Pure Data, its nearest relative, MFP is superficially +pretty similar but differs in a few key ways: + + * MFP uses Python data natively. Any literal data entered in the + UI is parsed by the Python evaluator, and any Python value is a + legitimate "message" on the dataflow network. This makes it much + easier to make patches that work like conventional "programs". + + * MFP provides fairly raw access to Python constructs if desired. + For example, the built-in Python console allows live coding of + Python functions as patch elements at runtime. + + * Name resolution and namespacing are addressed more robustly, + with explicit support for lexical scoping. This allows patches + to have a dynamic number of inputs and outputs, with hygienic + layer copying preserving the lexical structure of each "voice" + + * The UI is largely keyboard-driven, with a modal input system + that feels a bit like vim. The graphical presentation is a + single-window style with layers rather than multiple windows. + + * There is fairly deep integration of Open Sound Control (OSC), with + every patch element having an OSC address and the ability to learn + any other desired address. MIDI controller learning is also robustly + supported. + + * MFP has just a fraction of the builtin and addon functionality + provided by PD. It's not up to being a replacement except in + very limited cases! + +The code and issue tracker are hosted on GitHub: + + https://github.com/bgribble/mfp + +You can find the LAC-2013 paper and accompanying screenshots, +some sample patches, and a few other bits of documentation in the +doc directory of the GitHub repo. The README files at the top +level of the source tree contain dependency, build, and +getting-started information. + +More sample patches are in my personal patch repo: + + https://github.com/bgribble/mfp-patches + + +Where's it going? +---------------------------------------- + +I've been working on MFP as a spare time project for almost 14 +years now. The likelihood that it will ever have more than a few +users is low. Luckily, that doesn't bother me much; MFP is a +tool I am building mainly for my own use and education. + +That being said, if there's something about it that appeals to +you, I welcome your interest and participation. + +Thanks, +Bill Gribble + diff --git a/doc/count.mfp b/doc/count.mfp new file mode 100644 index 0000000..f4494f6 --- /dev/null +++ b/doc/count.mfp @@ -0,0 +1,305 @@ +{ + "gui_params": { + "display_type": "patch", + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, + "layers": [ + [ + "Layer 0", + "__patch__" + ] + ], + "name": "count", + "num_inlets": 1, + "num_outlets": 1, + "obj_id": 61, + "top_level": true, + "width": 0 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "62": { + "connections": [ + [ + [ + 63, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 115.041259765625, + "position_y": 285.07765197753906, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 54.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_018", + "osc_methods": [], + "properties": {}, + "type": "range" + }, + "63": { + "connections": [ + [ + [ + 66, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 115.041259765625, + "position_y": 333.07765197753906, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_019", + "osc_methods": [], + "properties": {}, + "type": "list" + }, + "64": { + "connections": [ + [ + [ + 68, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 113.06002807617188, + "position_y": 94.25257110595703, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 59.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_021", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "65": { + "connections": [ + [ + [ + 62, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 113.85763549804688, + "position_y": 228.2530288696289, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 57.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_023", + "osc_methods": [], + "properties": {}, + "type": "pack" + }, + "66": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 114.81446838378906, + "position_y": 384.44041442871094, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 70.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_020", + "osc_methods": [], + "properties": {}, + "type": "outlet" + }, + "68": { + "connections": [ + [ + [ + 87, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 114.29745483398438, + "position_y": 142.1174087524414, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 133.0 + }, + "initargs": "patch.args(0)", + "midi_filters": null, + "midi_mode": null, + "name": "processor_031", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": { + "__UninitType__": {} + } + }, + "87": { + "connections": [ + [ + [ + 65, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 114.81480407714844, + "position_y": 184.79879760742188, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_034", + "osc_methods": [], + "properties": {}, + "type": "int" + } + }, + "scopes": { + "__patch__": { + "patch": 61, + "processor_018": 62, + "processor_019": 63, + "processor_020": 66, + "processor_021": 64, + "processor_023": 65, + "processor_031": 68, + "processor_034": 87, + "self": 61 + } + }, + "type": "count" +} \ No newline at end of file diff --git a/doc/euclid.mfp b/doc/euclid.mfp new file mode 100644 index 0000000..f513c61 --- /dev/null +++ b/doc/euclid.mfp @@ -0,0 +1,1570 @@ +{ + "gui_params": { + "display_type": "patch", + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, + "layers": [ + [ + "Layer 0", + "__patch__" + ] + ], + "name": "euclid", + "num_inlets": 3, + "num_outlets": 1, + "obj_id": 590, + "top_level": true, + "width": 0 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "591": { + "connections": [ + [ + [ + 601, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.98757934570312, + "position_y": 299.2613067626953, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_025", + "osc_methods": [], + "properties": {}, + "type": "for" + }, + "592": { + "connections": [ + [ + [ + 626, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.0844497680664, + "position_y": 207.42596435546875, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 54.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_024", + "osc_methods": [], + "properties": {}, + "type": "count" + }, + "600": { + "connections": [ + [ + [ + 608, + 0 + ] + ], + [ + [ + 609, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 538.7819061279297, + "position_y": 182.57911682128906, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_038", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "601": { + "connections": [ + [ + [ + 622, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.36991119384766, + "position_y": 351.414306640625, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_016", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "602": { + "connections": [ + [ + [ + 606, + 0 + ] + ], + [ + [ + 607, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 603.857023810227, + "position_y": 265.7465291135518, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 81.0 + }, + "initargs": "True", + "midi_filters": null, + "midi_mode": null, + "name": "processor_042", + "osc_methods": [], + "properties": {}, + "type": "case" + }, + "603": { + "connections": [ + [ + [ + 604, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 197.5477752685547, + "position_y": 223.38870239257812, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_035", + "osc_methods": [], + "properties": {}, + "type": "/" + }, + "604": { + "connections": [ + [ + [ + 605, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 198.1441650390625, + "position_y": 261.5071716308594, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_012", + "osc_methods": [], + "properties": {}, + "type": "-" + }, + "605": { + "connections": [ + [ + [ + 608, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 324.37445068359375, + "position_y": 312.2206573486328, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_013", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": 11.0 + }, + "606": { + "connections": [ + [ + [ + 605, + 0 + ], + [ + 610, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 603.4512481689453, + "position_y": 307.87608337402344, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_006", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "607": { + "connections": [ + [ + [ + 608, + 1 + ], + [ + 611, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 669.5363616943359, + "position_y": 307.99327087402344, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "-1", + "midi_filters": null, + "midi_mode": null, + "name": "message_007", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "608": { + "connections": [ + [ + [ + 622, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 539.6228942871094, + "position_y": 396.94102478027344, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_014", + "osc_methods": [], + "properties": {}, + "type": "+" + }, + "609": { + "connections": [ + [ + [ + 602, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 603.7369232177734, + "position_y": 225.36109028311603, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 90.0 + }, + "initargs": "0.0001", + "midi_filters": null, + "midi_mode": null, + "name": "processor_041", + "osc_methods": [], + "properties": {}, + "type": "<=" + }, + "610": { + "connections": [ + [ + [ + 616, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 597.1724548339844, + "position_y": 387.14476013183594, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "message_012", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "611": { + "connections": [ + [ + [ + 616, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 646.6093139648438, + "position_y": 390.0251922607422, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "message_013", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "612": { + "connections": [ + [ + [ + 646, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.00698852539062, + "position_y": 93.26620483398438, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 59.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_002", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "613": { + "connections": [ + [ + [ + 644, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 261.95140075683594, + "position_y": 96.19496154785156, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 56.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_015", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "614": { + "connections": [ + [ + [ + 647, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 423.5753936767578, + "position_y": 94.47447204589844, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 58.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_016", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "615": { + "connections": [ + [ + [ + 642, + 0 + ], + [ + 643, + 0 + ], + [ + 645, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 271.25726318359375, + "position_y": 11.0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 79.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_019", + "osc_methods": [], + "properties": {}, + "type": "loadbang" + }, + "616": { + "connections": [ + [ + [ + 619, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 596.9485168457031, + "position_y": 439.4010925292969, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 57.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_020", + "osc_methods": [], + "properties": {}, + "type": "pack" + }, + "617": { + "connections": [ + [ + [ + 618, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 138.41134643554688, + "position_y": 353.4230651855469, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "[]", + "midi_filters": null, + "midi_mode": null, + "name": "message_002", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "618": { + "connections": [ + [ + [ + 620, + 0 + ], + [ + 624, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 423.2464904785156, + "position_y": 485.11529541015625, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_021", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": { + "__UninitType__": {} + } + }, + "619": { + "connections": [ + [ + [ + 621, + 0 + ] + ], + [ + [ + 620, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 596.9485168457031, + "position_y": 487.4010925292969, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_022", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "620": { + "connections": [ + [ + [ + 618, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 481.6878967285156, + "position_y": 489.0156555175781, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_023", + "osc_methods": [], + "properties": {}, + "type": "+" + }, + "621": { + "connections": [ + [ + [ + 618, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 424.08746337890625, + "position_y": 408.7834777832031, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_003", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "622": { + "connections": [ + [ + [ + 600, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 538.5256500244141, + "position_y": 126.16987609863281, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_037", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": { + "__UninitType__": {} + } + }, + "623": { + "connections": [ + [ + [ + 622, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 550.9091796875, + "position_y": 77.207275390625, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "message_010", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "624": { + "connections": [ + [ + [ + 630, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 369.5510559082031, + "position_y": 533.1152954101562, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_027", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": { + "__UninitType__": {} + } + }, + "625": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 368.35498046875, + "position_y": 616.3486938476562, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 70.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_028", + "osc_methods": [], + "properties": {}, + "type": "outlet" + }, + "626": { + "connections": [ + [ + [ + 628, + 0 + ] + ], + [ + [ + 591, + 0 + ] + ], + [ + [ + 617, + 0 + ], + [ + 623, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 67.4850845336914, + "position_y": 249.64955139160156, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "3", + "midi_filters": null, + "midi_mode": null, + "name": "processor_039", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "627": { + "connections": [ + [ + [ + 624, + 0 + ] + ], + [ + [ + 618, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 337.6087646484375, + "position_y": 411.637451171875, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_030", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "628": { + "connections": [ + [ + [ + 627, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 342.29150390625, + "position_y": 366.1037292480469, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_018", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "629": { + "connections": [ + [ + [ + 592, + 0 + ] + ], + [ + [ + 603, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.11189270019531, + "position_y": 171.42794799804688, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_031", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "630": { + "connections": [ + [ + [ + 625, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 369.5510559082031, + "position_y": 581.1152954101562, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 57.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_046", + "osc_methods": [], + "properties": {}, + "type": "rotate" + }, + "642": { + "connections": [ + [ + [ + 614, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 421.1850280761719, + "position_y": 51.07693672180176, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 145.0 + }, + "initargs": "patch.args(2) or 0", + "midi_filters": null, + "midi_mode": null, + "name": "message_005", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "643": { + "connections": [ + [ + [ + 613, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 272.0760498046875, + "position_y": 51.489990234375, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 143.0 + }, + "initargs": "patch.args(1) or 8", + "midi_filters": null, + "midi_mode": null, + "name": "message_004", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "644": { + "connections": [ + [ + [ + 603, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 262.104248046875, + "position_y": 179.1259307861328, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_018", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": 8 + }, + "645": { + "connections": [ + [ + [ + 646, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 121.70569610595703, + "position_y": 51.561275482177734, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 146.0 + }, + "initargs": "patch.args(0) or 8", + "midi_filters": null, + "midi_mode": null, + "name": "message_019", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "646": { + "connections": [ + [ + [ + 629, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 66.13702392578125, + "position_y": 137.329833984375, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_017", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": { + "__UninitType__": {} + } + }, + "647": { + "connections": [ + [ + [ + 630, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 423.5753936767578, + "position_y": 142.47447204589844, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_048", + "osc_methods": [], + "properties": {}, + "type": "int" + } + }, + "scopes": { + "__patch__": { + "message_002": 617, + "message_003": 621, + "message_004": 643, + "message_005": 642, + "message_006": 606, + "message_007": 607, + "message_010": 623, + "message_012": 610, + "message_013": 611, + "message_016": 601, + "message_018": 628, + "message_019": 645, + "patch": 590, + "processor_002": 612, + "processor_012": 604, + "processor_013": 605, + "processor_014": 608, + "processor_015": 613, + "processor_016": 614, + "processor_017": 646, + "processor_018": 644, + "processor_019": 615, + "processor_020": 616, + "processor_021": 618, + "processor_022": 619, + "processor_023": 620, + "processor_024": 592, + "processor_025": 591, + "processor_027": 624, + "processor_028": 625, + "processor_030": 627, + "processor_031": 629, + "processor_035": 603, + "processor_037": 622, + "processor_038": 600, + "processor_039": 626, + "processor_041": 609, + "processor_042": 602, + "processor_046": 630, + "processor_048": 647, + "self": 590 + } + }, + "type": "euclid" +} \ No newline at end of file diff --git a/doc/midi2cv.mfp b/doc/midi2cv.mfp new file mode 100644 index 0000000..9515074 --- /dev/null +++ b/doc/midi2cv.mfp @@ -0,0 +1,1030 @@ +{ + "gui_params": { + "display_type": "patch", + "dsp_outlets": [], + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, + "layers": [ + [ + "Layer 0", + "__patch__" + ] + ], + "name": "midi2cv", + "num_inlets": 1, + "num_outlets": 0, + "obj_id": 64, + "top_level": true, + "width": 0 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "100": { + "connections": [], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_018", + "obj_state": 3, + "position_x": 117.57783513523069, + "position_y": 304.3212946369071, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 58.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_018", + "osc_methods": [], + "properties": {}, + "type": "out~" + }, + "101": { + "connections": [], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_005", + "obj_state": 3, + "position_x": 320.50543212890625, + "position_y": 567.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 61.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_005", + "osc_methods": [], + "properties": {}, + "type": "out~" + }, + "102": { + "connections": [ + [ + [ + 91, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_006", + "obj_state": 3, + "position_x": 320.5070495605469, + "position_y": 413.1602783203125, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 51.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_006", + "osc_methods": [], + "properties": {}, + "type": "get" + }, + "103": { + "connections": [ + [ + [ + 106, + 0 + ] + ], + [ + [ + 67, + 0 + ] + ], + [ + [ + 104, + 0 + ] + ], + [ + [ + 118, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_002", + "obj_state": 3, + "position_x": 166.07438664890256, + "position_y": 75.76912483710241, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 337.0 + }, + "initargs": "NoteOn, NoteOff, MidiPitchbend, MidiCC", + "midi_filters": null, + "midi_mode": null, + "name": "processor_002", + "osc_methods": [], + "properties": {}, + "type": "case" + }, + "104": { + "connections": [ + [ + [ + 110, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_007", + "obj_state": 3, + "position_x": 391.9832458496094, + "position_y": 124.25491333007812, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 92.0 + }, + "initargs": "\"value\"", + "midi_filters": null, + "midi_mode": null, + "name": "processor_007", + "osc_methods": [], + "properties": {}, + "type": "get" + }, + "105": { + "connections": [ + [ + [ + 66, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_044", + "obj_state": 3, + "position_x": 251.4637908935547, + "position_y": 213.01348876953125, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 74.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_044", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "106": { + "connections": [ + [ + [ + 88, + 0 + ] + ], + [ + [ + 67, + 0 + ] + ], + [ + [ + 107, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_013", + "obj_state": 3, + "position_x": 166.07438664890256, + "position_y": 123.76912483710241, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "3", + "midi_filters": null, + "midi_mode": null, + "name": "processor_013", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "107": { + "connections": [ + [ + [ + 108, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "message_003", + "obj_state": 3, + "position_x": 338.0313415527344, + "position_y": 129.78138732910156, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "message_003", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "108": { + "connections": [ + [ + [ + 109, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_025", + "obj_state": 3, + "position_x": 391.9832458496094, + "position_y": 220.25491333007812, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 43.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_025", + "osc_methods": [], + "properties": {}, + "type": "sig~" + }, + "109": { + "connections": [ + [ + [ + 101, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_027", + "obj_state": 3, + "position_x": 320.50543212890625, + "position_y": 517.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_027", + "osc_methods": [], + "properties": {}, + "type": "+~" + }, + "110": { + "connections": [ + [ + [ + 108, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_022", + "obj_state": 3, + "position_x": 391.9832458496094, + "position_y": 172.25491333007812, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 66.0 + }, + "initargs": "81920", + "midi_filters": null, + "midi_mode": null, + "name": "processor_022", + "osc_methods": [], + "properties": {}, + "type": "/" + }, + "117": { + "connections": [], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_029", + "obj_state": 3, + "position_x": 524.0979614257812, + "position_y": 320.4832305908203, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 59.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_029", + "osc_methods": [], + "properties": {}, + "type": "out~" + }, + "118": { + "connections": [ + [ + [ + 119, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_030", + "obj_state": 3, + "position_x": 524.84619140625, + "position_y": 126.18930053710938, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 92.0 + }, + "initargs": "\"value\"", + "midi_filters": null, + "midi_mode": null, + "name": "processor_030", + "osc_methods": [], + "properties": {}, + "type": "get" + }, + "119": { + "connections": [ + [ + [ + 117, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_031", + "obj_state": 3, + "position_x": 523.7443237304688, + "position_y": 277.58876037597656, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 45.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_031", + "osc_methods": [], + "properties": {}, + "type": "ccv~" + }, + "65": { + "connections": [ + [ + [ + 103, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_001", + "obj_state": 3, + "position_x": 166.07438664890256, + "position_y": 27.76912483710241, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 66.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_001", + "osc_methods": [], + "properties": {}, + "type": "midi_in" + }, + "66": { + "connections": [ + [ + [ + 86, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_023", + "obj_state": 3, + "position_x": 252.50543212890625, + "position_y": 296.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 160.0 + }, + "initargs": "m: list(m.keys())", + "midi_filters": null, + "midi_mode": null, + "name": "processor_023", + "osc_methods": [], + "properties": {}, + "type": "func" + }, + "67": { + "connections": [ + [ + [ + 105, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_043", + "obj_state": 3, + "position_x": 251.4637908935547, + "position_y": 165.01348876953125, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 88.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_043", + "osc_methods": [], + "properties": {}, + "type": "track_keys" + }, + "86": { + "connections": [ + [ + [ + 87, + 0 + ] + ], + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_016", + "obj_state": 3, + "position_x": 252.50543212890625, + "position_y": 336.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 159.0 + }, + "initargs": "-1, default=None", + "midi_filters": null, + "midi_mode": null, + "name": "processor_016", + "osc_methods": [], + "properties": {}, + "type": "get" + }, + "87": { + "connections": [ + [ + [ + 90, + 0 + ] + ], + [ + [ + 102, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_003", + "obj_state": 3, + "position_x": 252.50543212890625, + "position_y": 378.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 78.0 + }, + "initargs": "None", + "midi_filters": null, + "midi_mode": null, + "name": "processor_003", + "osc_methods": [], + "properties": {}, + "type": "==:" + }, + "88": { + "connections": [ + [ + [ + 89, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "message_001", + "obj_state": 3, + "position_x": 118.07438664890256, + "position_y": 171.76912483710242, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 74.0 + }, + "initargs": "[(1, 10)]", + "midi_filters": null, + "midi_mode": null, + "name": "message_001", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "89": { + "connections": [ + [ + [ + 100, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_015", + "obj_state": 3, + "position_x": 117.57783513523069, + "position_y": 256.3212946369071, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 48.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_015", + "osc_methods": [], + "properties": {}, + "type": "line~" + }, + "90": { + "connections": [ + [ + [ + 89, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "message_002", + "obj_state": 3, + "position_x": 132.1999969482422, + "position_y": 210.3679962158203, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 77.0 + }, + "initargs": "[(0, 10)]", + "midi_filters": null, + "midi_mode": null, + "name": "message_002", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "91": { + "connections": [ + [ + [ + 109, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_004", + "obj_state": 3, + "position_x": 320.50543212890625, + "position_y": 469.2083740234375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 55.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_004", + "osc_methods": [], + "properties": {}, + "type": "note~" + } + }, + "scopes": { + "__patch__": { + "message_001": 88, + "message_002": 90, + "message_003": 107, + "patch": 64, + "processor_001": 65, + "processor_002": 103, + "processor_003": 87, + "processor_004": 91, + "processor_005": 101, + "processor_006": 102, + "processor_007": 104, + "processor_013": 106, + "processor_015": 89, + "processor_016": 86, + "processor_018": 100, + "processor_022": 110, + "processor_023": 66, + "processor_025": 108, + "processor_027": 109, + "processor_029": 117, + "processor_030": 118, + "processor_031": 119, + "processor_043": 67, + "processor_044": 105, + "self": 64 + } + }, + "type": "midi2cv" +} \ No newline at end of file diff --git a/doc/rand_euclid.mfp b/doc/rand_euclid.mfp new file mode 100644 index 0000000..99e4370 --- /dev/null +++ b/doc/rand_euclid.mfp @@ -0,0 +1,1977 @@ +{ + "gui_params": { + "display_type": "patch", + "dsp_inlets": [ + 0 + ], + "dsp_outlets": [ + 0, + 1 + ], + "export_h": 193.9948272705078, + "export_w": 243.67119598388672, + "export_x": 130.83629608154297, + "export_y": 60.41304016113281, + "height": 233.9948272705078, + "layers": [ + [ + "Layer 0", + "__patch__" + ], + [ + "Interface", + "__patch__" + ] + ], + "name": "rand_euclid", + "num_inlets": 1, + "num_outlets": 2, + "obj_id": 0, + "top_level": true, + "width": 520.4481201171875 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "1": { + "connections": [ + [ + [ + 2, + 0 + ] + ], + [ + [ + 14, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_019", + "obj_state": 3, + "position_x": 326.72265625, + "position_y": 305.3472595214844, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 77.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_019", + "osc_methods": [], + "properties": {}, + "type": "stepseq~" + }, + "10": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_007", + "obj_state": 3, + "position_x": 326.3772888183594, + "position_y": 655.5806274414062, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 79.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_007", + "osc_methods": [], + "properties": {}, + "type": "outlet~" + }, + "11": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_008", + "obj_state": 3, + "position_x": 418.0547790527344, + "position_y": 655.5088500976562, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 76.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_008", + "osc_methods": [], + "properties": {}, + "type": "outlet~" + }, + "117": { + "connections": [ + [ + [ + 98, + 2 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "rooty", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_011", + "obj_state": 3, + "position_x": 362.1732482910156, + "position_y": 182.96435546875, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rooty\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_011", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "12": { + "connections": [ + [ + [ + 6, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_013", + "obj_state": 3, + "position_x": 444.698486328125, + "position_y": 183.2938995361328, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 68.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_013", + "osc_methods": [], + "properties": {}, + "type": "inlet~" + }, + "124": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, + "is_export": false, + "layername": "Interface", + "no_export": false, + "obj_name": "text_001", + "obj_state": 3, + "position_x": 130.83629608154297, + "position_y": 88.087646484375, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "rng", + "width": 34.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_001", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "rng" + }, + "125": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, + "is_export": false, + "layername": "Interface", + "no_export": false, + "obj_name": "text_002", + "obj_state": 3, + "position_x": 170.9094009399414, + "position_y": 89.86695098876953, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "offset", + "width": 50.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_002", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "offset" + }, + "126": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, + "is_export": false, + "layername": "Interface", + "no_export": false, + "obj_name": "text_003", + "obj_state": 3, + "position_x": 223.0245819091797, + "position_y": 90.31212615966797, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "root", + "width": 40.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_003", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "root" + }, + "127": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, + "is_export": false, + "layername": "Interface", + "no_export": false, + "obj_name": "text_004", + "obj_state": 3, + "position_x": 264.60984802246094, + "position_y": 90.17477416992188, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "density", + "width": 61.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_004", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "density" + }, + "128": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, + "is_export": false, + "layername": "Interface", + "no_export": false, + "obj_name": "text_005", + "obj_state": 3, + "position_x": 319.5074920654297, + "position_y": 89.58255004882812, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "rotate", + "width": 53.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_005", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "rotate" + }, + "13": { + "connections": [ + [ + [ + 14, + 2 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_029", + "obj_state": 3, + "position_x": 517.6142883300781, + "position_y": 516.0335845947266, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 93.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_029", + "osc_methods": [], + "properties": {}, + "type": "bitcombine" + }, + "14": { + "connections": [ + [ + [ + 11, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_027", + "obj_state": 3, + "position_x": 422.6614074707031, + "position_y": 555.431884765625, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 148.0 + }, + "initargs": "16,65535", + "midi_filters": null, + "midi_mode": null, + "name": "processor_027", + "osc_methods": [], + "properties": {}, + "type": "pulsesel~" + }, + "15": { + "connections": [ + [ + [ + 13, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_028", + "obj_state": 3, + "position_x": 517.6142883300781, + "position_y": 478.03358459472656, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 88.0 + }, + "initargs": "16,6", + "midi_filters": null, + "midi_mode": null, + "name": "processor_028", + "osc_methods": [], + "properties": {}, + "type": "euclid" + }, + "2": { + "connections": [ + [ + [ + 3, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_021", + "obj_state": 3, + "position_x": 326.72265625, + "position_y": 353.3472595214844, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 56.0 + }, + "initargs": "1.0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_021", + "osc_methods": [], + "properties": {}, + "type": "*~" + }, + "3": { + "connections": [ + [ + [ + 5, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_022", + "obj_state": 3, + "position_x": 326.72265625, + "position_y": 401.3472595214844, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 46.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_022", + "osc_methods": [], + "properties": {}, + "type": "+~" + }, + "4": { + "connections": [ + [ + [ + 94, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_009", + "obj_state": 3, + "position_x": 326.81866455078125, + "position_y": 515.501708984375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 56.0 + }, + "initargs": "0.1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_009", + "osc_methods": [], + "properties": {}, + "type": "*~" + }, + "5": { + "connections": [ + [ + [ + 4, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_020", + "obj_state": 3, + "position_x": 326.81866455078125, + "position_y": 456.501708984375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 122.0 + }, + "initargs": "\"minor\"", + "midi_filters": null, + "midi_mode": null, + "name": "processor_020", + "osc_methods": [], + "properties": {}, + "type": "vcq12~" + }, + "6": { + "connections": [ + [ + [ + 1, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_016", + "obj_state": 3, + "position_x": 444.698486328125, + "position_y": 225.2938995361328, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 52.0 + }, + "initargs": "10", + "midi_filters": null, + "midi_mode": null, + "name": "processor_016", + "osc_methods": [], + "properties": {}, + "type": "*~" + }, + "7": { + "connections": [ + [ + [ + 98, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "reseed", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_001", + "obj_state": 3, + "position_x": 255.7901153564453, + "position_y": 182.98117065429688, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"reseed\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_001", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "73": { + "connections": [ + [ + [ + 89, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "rstrike", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_004", + "obj_state": 3, + "position_x": 517.2421875, + "position_y": 299.3222885131836, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rstrike\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_004", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "74": { + "connections": [ + [ + [ + 91, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "rrot", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_006", + "obj_state": 3, + "position_x": 598.028076171875, + "position_y": 298.527042388916, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rrot\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_006", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "75": { + "connections": [ + [ + [ + 87, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 100, + "is_export": false, + "layername": "Interface", + "max_value": 16.0, + "min_value": 0.0, + "no_export": false, + "obj_name": "slidemeter_004", + "obj_state": 3, + "orientation": 0, + "position_x": 280.265869140625, + "position_y": 114.42556762695312, + "position_z": 0, + "scale": null, + "scale_font_size": 7, + "scale_position": 0, + "scope": "__patch__", + "show_scale": false, + "style": {}, + "update_required": true, + "width": 25, + "zeropoint": null + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "slidemeter_004", + "osc_methods": [], + "properties": {}, + "type": "slidemeter", + "value": 16.0 + }, + "76": { + "connections": [ + [ + [ + 88, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 100, + "is_export": false, + "layername": "Interface", + "max_value": 16.0, + "min_value": 0.0, + "no_export": false, + "obj_name": "slidemeter_002", + "obj_state": 3, + "orientation": 0, + "position_x": 324.265869140625, + "position_y": 114.42556762695312, + "position_z": 0, + "scale": null, + "scale_font_size": 7, + "scale_position": 0, + "scope": "__patch__", + "show_scale": false, + "style": {}, + "update_required": true, + "width": 25, + "zeropoint": null + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "slidemeter_002", + "osc_methods": [], + "properties": {}, + "type": "slidemeter", + "value": 0.0 + }, + "77": { + "connections": [ + [ + [ + 85, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 100, + "is_export": false, + "layername": "Interface", + "max_value": 4.0, + "min_value": 0.0, + "no_export": false, + "obj_name": "slidemeter_006", + "obj_state": 3, + "orientation": 0, + "position_x": 134.3636474609375, + "position_y": 113.9315185546875, + "position_z": 0, + "scale": null, + "scale_font_size": 7, + "scale_position": 0, + "scope": "__patch__", + "show_scale": false, + "style": {}, + "update_required": true, + "width": 25, + "zeropoint": null + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "slidemeter_006", + "osc_methods": [], + "properties": {}, + "type": "slidemeter", + "value": 1 + }, + "78": { + "connections": [ + [ + [ + 86, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 100, + "is_export": false, + "layername": "Interface", + "max_value": 1.0, + "min_value": 0.0, + "no_export": false, + "obj_name": "slidemeter_003", + "obj_state": 3, + "orientation": 0, + "position_x": 180.9452667236328, + "position_y": 114.20846557617188, + "position_z": 0, + "scale": null, + "scale_font_size": 7, + "scale_position": 0, + "scope": "__patch__", + "show_scale": false, + "style": {}, + "update_required": true, + "width": 25, + "zeropoint": null + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "slidemeter_003", + "osc_methods": [], + "properties": {}, + "type": "slidemeter", + "value": 0.0 + }, + "79": { + "connections": [ + [ + [ + 84, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "button", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 30.0, + "is_export": false, + "label_text": "seed", + "layername": "Interface", + "message": null, + "no_export": false, + "obj_name": "button_001", + "obj_state": 3, + "position_x": 210.609619140625, + "position_y": 60.41304016113281, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 60.0 + }, + "initargs": "False", + "midi_filters": null, + "midi_mode": null, + "name": "button_001", + "osc_methods": [], + "properties": {}, + "type": "var" + }, + "8": { + "connections": [ + [ + [ + 2, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "range", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_002", + "obj_state": 3, + "position_x": 445.706298828125, + "position_y": 283.7528533935547, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"range\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_002", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "80": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "range", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_001", + "obj_state": 3, + "position_x": 131.8636474609375, + "position_y": 275.9315185546875, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"range\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_001", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "81": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "offset", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_002", + "obj_state": 3, + "position_x": 177.8636474609375, + "position_y": 291.9315185546875, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"offset\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_002", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "82": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "rstrike", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_003", + "obj_state": 3, + "position_x": 276.765869140625, + "position_y": 276.4255676269531, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rstrike\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_003", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "83": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "rrot", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_004", + "obj_state": 3, + "position_x": 322.765869140625, + "position_y": 290.4255676269531, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rrot\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_004", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "84": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "reseed", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_005", + "obj_state": 3, + "position_x": 82.1302261352539, + "position_y": 101.0634994506836, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"reseed\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_005", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "85": { + "connections": [ + [ + [ + 80, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "digits": 1, + "display_type": "enum", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Interface", + "max_value": null, + "min_value": null, + "no_export": false, + "obj_name": "enum_001", + "obj_state": 3, + "position_x": 133.48846435546875, + "position_y": 227.40786743164062, + "position_z": 0, + "scientific": false, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 41.0 + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "enum_001", + "osc_methods": [], + "properties": {}, + "type": "enum", + "value": 1 + }, + "86": { + "connections": [ + [ + [ + 81, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "digits": 1, + "display_type": "enum", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Interface", + "max_value": null, + "min_value": null, + "no_export": false, + "obj_name": "enum_002", + "obj_state": 3, + "position_x": 180.48846435546875, + "position_y": 227.40786743164062, + "position_z": 0, + "scientific": false, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 44.0 + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "enum_002", + "osc_methods": [], + "properties": {}, + "type": "enum", + "value": 0.0 + }, + "87": { + "connections": [ + [ + [ + 82, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "digits": 0, + "display_type": "enum", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Interface", + "max_value": null, + "min_value": null, + "no_export": false, + "obj_name": "enum_003", + "obj_state": 3, + "position_x": 278.80902099609375, + "position_y": 227.37640380859375, + "position_z": 0, + "scientific": false, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 36.0 + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "enum_003", + "osc_methods": [], + "properties": {}, + "type": "enum", + "value": 16.0 + }, + "88": { + "connections": [ + [ + [ + 83, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "digits": 0, + "display_type": "enum", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Interface", + "max_value": null, + "min_value": null, + "no_export": false, + "obj_name": "enum_004", + "obj_state": 3, + "position_x": 324.80902099609375, + "position_y": 226.37640380859375, + "position_z": 0, + "scientific": false, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "enum_004", + "osc_methods": [], + "properties": {}, + "type": "enum", + "value": 0.0 + }, + "89": { + "connections": [ + [ + [ + 90, + 0 + ] + ], + [ + [ + 15, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_002", + "obj_state": 3, + "position_x": 517.9620361328125, + "position_y": 343.42556381225586, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 74.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_002", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "9": { + "connections": [ + [ + [ + 3, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "recvvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 37.5, + "is_export": false, + "label_text": "offset", + "layername": "Layer 0", + "no_export": false, + "obj_name": "recvvia_003", + "obj_state": 3, + "position_x": 422.89849853515625, + "position_y": 343.1171569824219, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"offset\",0", + "midi_filters": null, + "midi_mode": null, + "name": "recvvia_003", + "osc_methods": [], + "properties": {}, + "type": "recv" + }, + "90": { + "connections": [ + [ + [ + 93, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "message_001", + "obj_state": 3, + "position_x": 517.9620361328125, + "position_y": 380.4255676269531, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 56.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_001", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "91": { + "connections": [ + [ + [ + 90, + 0 + ] + ], + [ + [ + 15, + 2 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_003", + "obj_state": 3, + "position_x": 602.528076171875, + "position_y": 341.527042388916, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 74.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_003", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "92": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_023", + "obj_state": 3, + "position_x": 194.67100524902344, + "position_y": 302.3951873779297, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 94.0 + }, + "initargs": "\"seq:\"", + "midi_filters": null, + "midi_mode": null, + "name": "processor_023", + "osc_methods": [], + "properties": {}, + "type": "print" + }, + "93": { + "connections": [ + [ + [ + 15, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_004", + "obj_state": 3, + "position_x": 517.9620361328125, + "position_y": 428.4255676269531, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 99.0 + }, + "initargs": "100", + "midi_filters": null, + "midi_mode": null, + "name": "processor_004", + "osc_methods": [], + "properties": {}, + "type": "throttle" + }, + "94": { + "connections": [ + [ + [ + 10, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_010", + "obj_state": 3, + "position_x": 326.81866455078125, + "position_y": 582.501708984375, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 67.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_010", + "osc_methods": [], + "properties": {}, + "type": "slew~" + }, + "95": { + "connections": [ + [ + [ + 96, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 100, + "is_export": false, + "layername": "Interface", + "max_value": 1.0, + "min_value": 0.0, + "no_export": false, + "obj_name": "slidemeter_041", + "obj_state": 3, + "orientation": 0, + "position_x": 228.25225830078125, + "position_y": 115.08656311035156, + "position_z": 0, + "scale": null, + "scale_font_size": 7, + "scale_position": 0, + "scope": "__patch__", + "show_scale": false, + "style": {}, + "update_required": true, + "width": 25, + "zeropoint": null + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "slidemeter_041", + "osc_methods": [], + "properties": {}, + "type": "slidemeter", + "value": 0.1 + }, + "96": { + "connections": [ + [ + [ + 97, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "digits": 1, + "display_type": "enum", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Interface", + "max_value": null, + "min_value": null, + "no_export": false, + "obj_name": "enum_041", + "obj_state": 3, + "position_x": 228.98789978027344, + "position_y": 226.94232177734375, + "position_z": 0, + "scientific": false, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 41.0 + }, + "initargs": "0.0", + "midi_filters": null, + "midi_mode": null, + "name": "enum_041", + "osc_methods": [], + "properties": {}, + "type": "enum", + "value": 0.1 + }, + "97": { + "connections": [ + [] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "sendvia", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 35, + "is_export": false, + "label_text": "rooty", + "layername": "Interface", + "no_export": false, + "obj_name": "sendvia_011", + "obj_state": 3, + "position_x": 226.92893981933594, + "position_y": 288.4862060546875, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": false, + "width": 20 + }, + "initargs": "\"rooty\",0", + "midi_filters": null, + "midi_mode": null, + "name": "sendvia_011", + "osc_methods": [], + "properties": {}, + "type": "send" + }, + "98": { + "connections": [ + [ + [ + 1, + 0 + ], + [ + 92, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "obj_name": "processor_017", + "obj_state": 3, + "position_x": 260.96722412109375, + "position_y": 241.0345916748047, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 111.0 + }, + "initargs": "1,0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_017", + "osc_methods": [], + "properties": {}, + "type": "randseq16" + } + }, + "scopes": { + "__patch__": { + "button_001": 79, + "enum_001": 85, + "enum_002": 86, + "enum_003": 87, + "enum_004": 88, + "enum_041": 96, + "message_001": 90, + "patch": 0, + "processor_002": 89, + "processor_003": 91, + "processor_004": 93, + "processor_007": 10, + "processor_008": 11, + "processor_009": 4, + "processor_010": 94, + "processor_013": 12, + "processor_016": 6, + "processor_017": 98, + "processor_019": 1, + "processor_020": 5, + "processor_021": 2, + "processor_022": 3, + "processor_023": 92, + "processor_027": 14, + "processor_028": 15, + "processor_029": 13, + "recvvia_001": 7, + "recvvia_002": 8, + "recvvia_003": 9, + "recvvia_004": 73, + "recvvia_006": 74, + "recvvia_011": 117, + "self": 0, + "sendvia_001": 80, + "sendvia_002": 81, + "sendvia_003": 82, + "sendvia_004": 83, + "sendvia_005": 84, + "sendvia_011": 97, + "slidemeter_002": 76, + "slidemeter_003": 78, + "slidemeter_004": 75, + "slidemeter_006": 77, + "slidemeter_041": 95, + "text_001": 124, + "text_002": 125, + "text_003": 126, + "text_004": 127, + "text_005": 128 + } + }, + "type": "rand_euclid" +} \ No newline at end of file diff --git a/doc/randseq16.mfp b/doc/randseq16.mfp new file mode 100644 index 0000000..288e0b2 --- /dev/null +++ b/doc/randseq16.mfp @@ -0,0 +1,767 @@ +{ + "gui_params": { + "display_type": "patch", + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, + "layers": [ + [ + "Layer 0", + "__patch__" + ] + ], + "name": "randseq16", + "num_inlets": 3, + "num_outlets": 1, + "obj_id": 758, + "top_level": true, + "width": 0 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "759": { + "connections": [ + [ + [ + 760, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 144.93972778320312, + "position_y": 149.13192749023438, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 35 + }, + "initargs": "[]", + "midi_filters": null, + "midi_mode": null, + "name": "message_002", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "760": { + "connections": [ + [ + [ + 763, + 1 + ], + [ + 768, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 112.25936889648438, + "position_y": 295.156494140625, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_004", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": [ + 0.6550948898769098, + 0.8867189935155819, + 0.8982852701706747, + 0.13851769607074438, + 0.09070482622547849, + 0.6904606491962568, + 0.3754928997097129, + 0.7821796252376456, + 0.9741753144556298, + 0.2859677971792238, + 0.6159751591056158, + 0.810365873029986, + 0.41235414055551034, + 0.46709955280407267, + 0.91970131359734 + ] + }, + "761": { + "connections": [ + [ + [ + 762, + 0 + ] + ], + [ + [ + 764, + 0 + ] + ], + [ + [ + 759, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 78.52005004882812, + "position_y": 103.98812103271484, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "3", + "midi_filters": null, + "midi_mode": null, + "name": "processor_003", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "762": { + "connections": [ + [ + [ + 763, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 78.38330078125, + "position_y": 342.8661193847656, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_003", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "763": { + "connections": [ + [ + [ + 771, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 78.38330078125, + "position_y": 390.8661193847656, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_005", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": [ + 0.6550948898769098, + 0.8867189935155819, + 0.8982852701706747, + 0.13851769607074438, + 0.09070482622547849, + 0.6904606491962568, + 0.3754928997097129, + 0.7821796252376456, + 0.9741753144556298, + 0.2859677971792238, + 0.6159751591056158, + 0.810365873029986, + 0.41235414055551034, + 0.46709955280407267, + 0.91970131359734 + ] + }, + "764": { + "connections": [ + [ + [ + 767, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 112.52487182617188, + "position_y": 195.5463104248047, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 105.0 + }, + "initargs": "range(16)", + "midi_filters": null, + "midi_mode": null, + "name": "processor_006", + "osc_methods": [], + "properties": {}, + "type": "for" + }, + "765": { + "connections": [ + [ + [ + 776, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 278.4956970214844, + "position_y": 322.6681213378906, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 148.0 + }, + "initargs": ",random.random()", + "midi_filters": null, + "midi_mode": null, + "name": "message_004", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "766": { + "connections": [ + [ + [ + 769, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 282.0722351074219, + "position_y": 531.6245422363281, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 57.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_009", + "osc_methods": [], + "properties": {}, + "type": "pack" + }, + "767": { + "connections": [ + [ + [ + 760, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 112.52487182617188, + "position_y": 243.5463104248047, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_005", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "768": { + "connections": [ + [ + [ + 769, + 0 + ] + ], + [ + [ + 765, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 205.83023071289062, + "position_y": 278.6659240722656, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_010", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "769": { + "connections": [ + [ + [ + 760, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 205.90274047851562, + "position_y": 321.3663330078125, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_011", + "osc_methods": [], + "properties": {}, + "type": "+" + }, + "770": { + "connections": [ + [ + [ + 761, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 79.0852279663086, + "position_y": 63.623779296875, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 59.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_002", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "771": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 78.38330078125, + "position_y": 438.8661193847656, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 70.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_007", + "osc_methods": [], + "properties": {}, + "type": "outlet" + }, + "772": { + "connections": [ + [ + [ + 775, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 410.8857421875, + "position_y": 174.72591400146484, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 56.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_012", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "773": { + "connections": [ + [ + [ + 776, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 516.0383605957031, + "position_y": 176.96129608154297, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 58.0 + }, + "initargs": "2", + "midi_filters": null, + "midi_mode": null, + "name": "processor_013", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "774": { + "connections": [ + [ + [ + 775, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 278.1715087890625, + "position_y": 422.21380615234375, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 58.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_008", + "osc_methods": [], + "properties": {}, + "type": "max" + }, + "775": { + "connections": [ + [ + [ + 766, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 281.805908203125, + "position_y": 476.2185974121094, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 149.0 + }, + "initargs": "patch.args(0) or 1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_014", + "osc_methods": [], + "properties": {}, + "type": "*" + }, + "776": { + "connections": [ + [ + [ + 774, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 278.1715087890625, + "position_y": 374.21380615234375, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 148.0 + }, + "initargs": "patch.args(1) or 0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_015", + "osc_methods": [], + "properties": {}, + "type": "-" + } + }, + "scopes": { + "__patch__": { + "message_002": 759, + "message_003": 762, + "message_004": 765, + "message_005": 767, + "patch": 758, + "processor_002": 770, + "processor_003": 761, + "processor_004": 760, + "processor_005": 763, + "processor_006": 764, + "processor_007": 771, + "processor_008": 774, + "processor_009": 766, + "processor_010": 768, + "processor_011": 769, + "processor_012": 772, + "processor_013": 773, + "processor_014": 775, + "processor_015": 776, + "self": 758 + } + }, + "type": "randseq16" +} \ No newline at end of file diff --git a/doc/rotate.mfp b/doc/rotate.mfp new file mode 100644 index 0000000..b8e9f2e --- /dev/null +++ b/doc/rotate.mfp @@ -0,0 +1,461 @@ +{ + "gui_params": { + "display_type": "patch", + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, + "layers": [ + [ + "Layer 0", + "__patch__" + ] + ], + "name": "rotate", + "width": 0 + }, + "hot_inlets": [ + 0 + ], + "objects": { + "10": { + "connections": [ + [ + [ + 13, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 263.7010192871094, + "position_y": 37.34632110595703, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 45.0 + }, + "initargs": "1", + "midi_filters": null, + "midi_mode": null, + "name": "processor_004", + "osc_methods": [], + "properties": {}, + "type": "inlet" + }, + "11": { + "connections": [ + [ + [ + 12, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 339.2048645019531, + "position_y": 46.698219299316406, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 79.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_005", + "osc_methods": [], + "properties": {}, + "type": "loadbang" + }, + "12": { + "connections": [ + [ + [ + 13, + 1 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 339.2048645019531, + "position_y": 94.69821166992188, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 113.0 + }, + "initargs": "patch.args(0)", + "midi_filters": null, + "midi_mode": null, + "name": "message_002", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "13": { + "connections": [ + [ + [ + 28, + 1 + ], + [ + 29, + 2 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 238.69186401367188, + "position_y": 150.55604553222656, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 36.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_006", + "osc_methods": [], + "properties": {}, + "type": "var", + "value": 2 + }, + "17": { + "connections": [ + [ + [ + 28, + 0 + ] + ], + [ + [ + 29, + 0 + ] + ], + [ + [ + 18, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 97.77828979492188, + "position_y": 83.3123779296875, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 75.0 + }, + "initargs": "3", + "midi_filters": null, + "midi_mode": null, + "name": "processor_007", + "osc_methods": [], + "properties": {}, + "type": "trigger" + }, + "18": { + "connections": [ + [ + [ + 13, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 238.01602172851562, + "position_y": 112.86557006835938, + "scope": "__patch__", + "style": {}, + "update_required": true, + "width": 57.0 + }, + "initargs": "Bang", + "midi_filters": null, + "midi_mode": null, + "name": "message_003", + "osc_methods": [], + "properties": {}, + "type": "message" + }, + "19": { + "connections": [ + [ + [ + 34, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 102.69966125488281, + "position_y": 255.83212280273438, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_009", + "osc_methods": [], + "properties": {}, + "type": "+" + }, + "28": { + "connections": [ + [ + [ + 19, + 0 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 82.72379302978516, + "position_y": 205.05691528320312, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 46 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_010", + "osc_methods": [], + "properties": {}, + "type": "slice" + }, + "29": { + "connections": [ + [ + [ + 19, + 1 + ] + ] + ], + "do_onload": true, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 138.6996612548828, + "position_y": 204.83212280273438, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 46 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "processor_008", + "osc_methods": [], + "properties": {}, + "type": "slice" + }, + "34": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 102.69966125488281, + "position_y": 303.8321228027344, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 56.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_011", + "osc_methods": [], + "properties": {}, + "type": "outlet" + }, + "9": { + "connections": [ + [ + [ + 17, + 0 + ] + ] + ], + "do_onload": false, + "gui_params": { + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, + "is_export": false, + "layername": "Layer 0", + "no_export": false, + "position_x": 97.77828979492188, + "position_y": 35.3123779296875, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 45.0 + }, + "initargs": "0", + "midi_filters": null, + "midi_mode": null, + "name": "processor_003", + "osc_methods": [], + "properties": {}, + "type": "inlet" + } + }, + "scopes": { + "__patch__": { + "message_002": 12, + "message_003": 18, + "patch": 0, + "processor_003": 9, + "processor_004": 10, + "processor_005": 11, + "processor_006": 13, + "processor_007": 17, + "processor_008": 29, + "processor_009": 19, + "processor_010": 28, + "processor_011": 34, + "self": 0 + } + }, + "type": "rotate" +} \ No newline at end of file diff --git a/doc/tutorial.mfp b/doc/tutorial.mfp index 0a8e459..a714730 100644 --- a/doc/tutorial.mfp +++ b/doc/tutorial.mfp @@ -1,6 +1,11 @@ { "gui_params": { "display_type": "patch", + "export_h": null, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 20, "layers": [ [ "0. Introduction", @@ -67,87 +72,117 @@ "__patch__" ] ], - "name": "tutorial" + "name": "tutorial", + "num_inlets": 1, + "num_outlets": 0, + "obj_id": 0, + "top_level": true, + "width": 0 }, "hot_inlets": [ 0 ], "objects": { - "10": { + "1": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 194.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 39.0, "is_export": false, - "layername": "1. Command line", + "layername": "0. Introduction", "no_export": false, - "position_x": 57.91237258911133, - "position_y": 80.91848754882812, - "scope": "", + "obj_name": "text_002", + "obj_state": 3, + "position_x": 35.56041717529297, + "position_y": 25.977832794189453, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "You have gotten this far, which is good news! You know how to open a patch file. \nIn case you forgot already: \n mfp [options] [filename ...] \n\nTo see a complete list of command-line options:\n mfp --help\n\nTo see a list of all builtin objects with a brief description: \n mfp --help-builtins", - "width": 548.0 + "value": "MFP Tutorial", + "width": 174.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_018", + "name": "text_002", "osc_methods": [], "properties": {}, "type": "text", - "value": "You have gotten this far, which is good news! You know how to open a patch file. \nIn case you forgot already: \n mfp [options] [filename ...] \n\nTo see a complete list of command-line options:\n mfp --help\n\nTo see a list of all builtin objects with a brief description: \n mfp --help-builtins" + "value": "MFP Tutorial" }, - "100": { + "10": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 89.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, - "layername": "13. Pattern: Conditionals 3", + "layername": "1. Command line", "no_export": false, - "position_x": 43.88772201538086, - "position_y": 81.19505310058594, + "obj_name": "text_019", + "obj_state": 3, + "position_x": 35.56041717529297, + "position_y": 25.977832794189453, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "value": "One last important thing: in both [route] and [case], if the objects \nto test against are Python type objects, any object of the indicated type \nwill match. Tests are done in left-to-right order with the first successful match\naccepted. ", - "width": 525.0 + "value": "Command line", + "width": 161.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_058", + "name": "text_019", "osc_methods": [], "properties": {}, "type": "text", - "value": "One last important thing: in both [route] and [case], if the objects \nto test against are Python type objects, any object of the indicated type \nwill match. Tests are done in left-to-right order with the first successful match\naccepted. " + "value": "Command line" }, - "101": { + "100": { "connections": [ [ [ - 104, + 103, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "message_018", + "obj_state": 3, "position_x": 68.892333984375, "position_y": 197.7730712890625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 69.0 + "width": 67.0 }, "initargs": "12.345", "midi_filters": null, @@ -157,27 +192,34 @@ "properties": {}, "type": "message" }, - "102": { + "101": { "connections": [ [ [ - 104, + 103, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "message_019", + "obj_state": 3, "position_x": 146.7159881591797, "position_y": 199.30589294433594, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 64.0 + "width": 68.0 }, "initargs": "\"hello\"", "midi_filters": null, @@ -187,27 +229,34 @@ "properties": {}, "type": "message" }, - "103": { + "102": { "connections": [ [ [ - 104, + 103, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "message_020", + "obj_state": 3, "position_x": 278.56463623046875, "position_y": 201.72451782226562, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 65.0 + "width": 62.0 }, "initargs": "(1,2,3)", "midi_filters": null, @@ -217,52 +266,63 @@ "properties": {}, "type": "message" }, - "104": { + "103": { "connections": [ [ [ - 105, + 104, 0 ] ], [ [ - 106, + 105, 0 ] ], [ [ - 107, + 106, 0 ] ], [ [ - 108, + 107, 0 ] ], [ [ - 109, + 108, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_021", + "obj_state": 3, "position_x": 105.8345718383789, "position_y": 266.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 197.0 + "width": 208.0 }, "initargs": "\"hello\", str, tuple, float", "midi_filters": null, @@ -272,23 +332,34 @@ "properties": {}, "type": "case" }, - "105": { + "104": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_022", + "obj_state": 3, "position_x": 105.8345718383789, "position_y": 314.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 139.0 + "width": 150.0 }, "initargs": "\"it was hello:\"", "midi_filters": null, @@ -298,23 +369,34 @@ "properties": {}, "type": "print" }, - "106": { + "105": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_023", + "obj_state": 3, "position_x": 150.8345718383789, "position_y": 344.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 243.0 + "width": 263.0 }, "initargs": "\"it was a string but not hello:\"", "midi_filters": null, @@ -324,23 +406,34 @@ "properties": {}, "type": "print" }, - "107": { + "106": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_024", + "obj_state": 3, "position_x": 198.8345718383789, "position_y": 374.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 152.0 + "width": 164.0 }, "initargs": "\"it was a tuple:\"", "midi_filters": null, @@ -350,23 +443,34 @@ "properties": {}, "type": "print" }, - "108": { + "107": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_025", + "obj_state": 3, "position_x": 245.8345718383789, "position_y": 404.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 148.0 + "width": 161.0 }, "initargs": "\"it was a float:\"", "midi_filters": null, @@ -376,23 +480,34 @@ "properties": {}, "type": "print" }, - "109": { + "108": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "processor_026", + "obj_state": 3, "position_x": 292.8345718383789, "position_y": 434.13958740234375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 206.0 + "width": 222.0 }, "initargs": "\"it was something else:\"", "midi_filters": null, @@ -402,84 +517,107 @@ "properties": {}, "type": "print" }, - "11": { + "109": { "connections": [ - [] + [ + [ + 103, + 0 + ] + ] ], "do_onload": false, "gui_params": { - "display_type": "text", - "height": 26.0, + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, - "layername": "1. Command line", + "layername": "13. Pattern: Conditionals 3", "no_export": false, - "position_x": 35.56041717529297, - "position_y": 25.977832794189453, - "scope": "", + "obj_name": "message_021", + "obj_state": 3, + "position_x": 220.6551513671875, + "position_y": 200.89918518066406, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "Command line", - "width": 102.0 + "width": 57.0 }, - "initargs": null, + "initargs": "\"foo\"", "midi_filters": null, "midi_mode": null, - "name": "text_019", + "name": "message_021", "osc_methods": [], "properties": {}, - "type": "text", - "value": "Command line" + "type": "message" }, - "110": { + "11": { "connections": [ - [ - [ - 104, - 0 - ] - ] + [] ], "do_onload": false, "gui_params": { - "display_type": "message", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, - "layername": "13. Pattern: Conditionals 3", + "layername": "0. Introduction", "no_export": false, - "position_x": 220.6551513671875, - "position_y": 200.89918518066406, + "obj_name": "text_020", + "obj_state": 3, + "position_x": 48.98456954956055, + "position_y": 94.84783172607422, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 53.0 + "value": "Welcome to MFP, Music For Programmers. This tutorial should give you enough basics\nto begin to create and use your own patches. ", + "width": 622.0 }, - "initargs": "\"foo\"", + "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "message_021", + "name": "text_020", "osc_methods": [], "properties": {}, - "type": "message" + "type": "text", + "value": "Welcome to MFP, Music For Programmers. This tutorial should give you enough basics\nto begin to create and use your own patches. " }, - "111": { + "110": { "connections": [ [ [ - 104, + 103, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "message_022", + "obj_state": 3, "position_x": 353.4476013183594, "position_y": 203.89767456054688, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 49.0 + "width": 52.0 }, "initargs": "True", "midi_filters": null, @@ -489,23 +627,32 @@ "properties": {}, "type": "message" }, - "112": { + "111": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "text_059", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Metronome", - "width": 142.0 + "width": 221.0 }, "initargs": null, "midi_filters": null, @@ -516,23 +663,32 @@ "type": "text", "value": "Pattern: Metronome" }, - "113": { + "112": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 110.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 105.0, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "text_060", + "obj_state": 3, "position_x": 60.35821533203125, "position_y": 91.02922058105469, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "If you want things to happen in a rhythm, you can use a [metro] \nto do it. [metro] outputs a Bang periodically. The interval between \nBangs is specified either in the init args or on the right inlet, in milliseconds \nin either case. The metronome is started with a True or Bang on its left inlet\nand stopped with a False.", - "width": 506.0 + "width": 544.0 }, "initargs": null, "midi_filters": null, @@ -543,27 +699,34 @@ "type": "text", "value": "If you want things to happen in a rhythm, you can use a [metro] \nto do it. [metro] outputs a Bang periodically. The interval between \nBangs is specified either in the init args or on the right inlet, in milliseconds \nin either case. The metronome is started with a True or Bang on its left inlet\nand stopped with a False." }, - "114": { + "113": { "connections": [ [ [ - 116, + 115, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "message_023", + "obj_state": 3, "position_x": 155.76284790039062, "position_y": 232.83914184570312, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 49.0 + "width": 52.0 }, "initargs": "True", "midi_filters": null, @@ -573,27 +736,34 @@ "properties": {}, "type": "message" }, - "115": { + "114": { "connections": [ [ [ - 116, + 115, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "message_024", + "obj_state": 3, "position_x": 168.66433715820312, "position_y": 266.80804443359375, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 54.0 + "width": 56.0 }, "initargs": "False", "midi_filters": null, @@ -603,28 +773,39 @@ "properties": {}, "type": "message" }, - "116": { + "115": { "connections": [ [ [ - 117, + 116, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "processor_027", + "obj_state": 3, "position_x": 155.7628631591797, "position_y": 324.6950378417969, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 93.0 + "width": 98.0 }, "initargs": "1000", "midi_filters": null, @@ -634,23 +815,34 @@ "properties": {}, "type": "metro" }, - "117": { + "116": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "processor_028", + "obj_state": 3, "position_x": 155.7628631591797, "position_y": 372.6950378417969, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 44.0 + "width": 48.0 }, "initargs": null, "midi_filters": null, @@ -660,31 +852,38 @@ "properties": {}, "type": "print" }, - "118": { + "117": { "connections": [ [ [ - 119, + 118, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "digits": 1, "display_type": "enum", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "max_value": null, "min_value": null, "no_export": false, + "obj_name": "enum_002", + "obj_state": 3, "position_x": 239.68123535156235, "position_y": 236.4311981201172, + "position_z": 0, "scientific": false, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 69.0 + "width": 71.0 }, "initargs": "1000.0", "midi_filters": null, @@ -695,34 +894,45 @@ "type": "enum", "value": 1000 }, - "119": { + "118": { "connections": [ [ [ - 116, + 115, 1 ] ], [ [ - 120, + 119, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "14: Pattern: Metronome", "no_export": false, + "obj_name": "processor_029", + "obj_state": 3, "position_x": 239.68123535156235, "position_y": 284.43121337890625, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 70.0 + "width": 74.0 }, "initargs": "2", "midi_filters": null, @@ -732,76 +942,105 @@ "properties": {}, "type": "trigger" }, - "12": { + "119": { "connections": [ [] ], - "do_onload": false, + "do_onload": true, "gui_params": { - "display_type": "text", - "height": 47.0, + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, - "layername": "0. Introduction", + "layername": "14: Pattern: Metronome", "no_export": false, - "position_x": 48.98456954956055, - "position_y": 94.84783172607422, - "scope": "", - "update_required": true, - "value": "Welcome to MFP, Music For Programmers. This tutorial should give you enough basics\nto begin to create and use your own patches. ", - "width": 571.0 + "obj_name": "processor_030", + "obj_state": 3, + "position_x": 300.1900434570311, + "position_y": 324.50067138671875, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 290.0 }, - "initargs": null, + "initargs": "\"setting metro interval to %s ms\"", "midi_filters": null, "midi_mode": null, - "name": "text_020", + "name": "processor_030", "osc_methods": [], "properties": {}, - "type": "text", - "value": "Welcome to MFP, Music For Programmers. This tutorial should give you enough basics\nto begin to create and use your own patches. " + "type": "print" }, - "120": { + "12": { "connections": [ [] ], - "do_onload": true, + "do_onload": false, "gui_params": { - "display_type": "processor", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, "is_export": false, - "layername": "14: Pattern: Metronome", + "layername": "1. Command line", "no_export": false, - "position_x": 300.1900434570311, - "position_y": 324.50067138671875, + "obj_name": "text_021", + "obj_state": 3, + "position_x": 58.97983169555664, + "position_y": 288.694580078125, + "position_z": 0, "scope": "__patch__", - "show_label": true, - "update_required": false, - "width": 263.0 + "style": {}, + "update_required": true, + "value": "Note especially the -v option, which copies all log messages to the console. \nThis may be helpful if a problem is causing MFP to crash and take log messages \nwith it. Usually, after startup all log messages will go to the \"Log\" tab below, but \nwill not be printed to stdout.", + "width": 584.0 }, - "initargs": "\"setting metro interval to %s ms\"", + "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "processor_030", + "name": "text_021", "osc_methods": [], "properties": {}, - "type": "print" + "type": "text", + "value": "Note especially the -v option, which copies all log messages to the console. \nThis may be helpful if a problem is causing MFP to crash and take log messages \nwith it. Usually, after startup all log messages will go to the \"Log\" tab below, but \nwill not be printed to stdout." }, - "121": { + "120": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 35.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "text_061", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Functions", - "width": 191.0 + "width": 201.0 }, "initargs": null, "midi_filters": null, @@ -812,23 +1051,32 @@ "type": "text", "value": "Pattern: Functions" }, - "122": { + "121": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 215.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 205.0, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "text_062", + "obj_state": 3, "position_x": 55.81477355957031, "position_y": 76.21011352539062, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "Mathematical functions can be defined in dataflow style or using the [func] \nbuiltin. [func] will be slightly more efficient and may be clearer to read, but \nboth work fine.\n\nSay we have a number coming in and need to take that value x and compute the \nfunction: \n\n y = 3*x^2 + 4*x + 5\n\nTwo ways to do it: ", - "width": 533.0 + "width": 575.0 }, "initargs": null, "midi_filters": null, @@ -839,35 +1087,42 @@ "type": "text", "value": "Mathematical functions can be defined in dataflow style or using the [func] \nbuiltin. [func] will be slightly more efficient and may be clearer to read, but \nboth work fine.\n\nSay we have a number coming in and need to take that value x and compute the \nfunction: \n\n y = 3*x^2 + 4*x + 5\n\nTwo ways to do it: " }, - "123": { + "122": { "connections": [ [ [ - 124, + 123, 0 ], [ - 131, + 129, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "digits": 1, "display_type": "enum", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "max_value": null, "min_value": null, "no_export": false, + "obj_name": "enum_003", + "obj_state": 3, "position_x": 341.5330810546875, "position_y": 262.64605712890625, + "position_z": 0, "scientific": false, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 42.0 + "width": 44.0 }, "initargs": "0.0", "midi_filters": null, @@ -876,42 +1131,53 @@ "osc_methods": [], "properties": {}, "type": "enum", - "value": 0 + "value": 0.0 }, - "124": { + "123": { "connections": [ [ [ - 128, + 126, 0 ] ], [ [ - 128, + 126, 1 ] ], [ [ - 126, + 124, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_031", + "obj_state": 3, "position_x": 404.4472351074219, "position_y": 295.7294616699219, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 70.0 + "width": 75.0 }, "initargs": "3", "midi_filters": null, @@ -921,26 +1187,37 @@ "properties": {}, "type": "trigger" }, - "126": { + "124": { "connections": [ [ [ - 127, + 125, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_033", + "obj_state": 3, "position_x": 465.3640441894531, "position_y": 335.4204406738281, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, "width": 36.0 }, @@ -952,28 +1229,39 @@ "properties": {}, "type": "*" }, - "127": { + "125": { "connections": [ [ [ - 130, + 128, 1 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_032", + "obj_state": 3, "position_x": 465.3668212890625, "position_y": 374.3493957519531, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 37.0 + "width": 36.0 }, "initargs": "5", "midi_filters": null, @@ -983,26 +1271,37 @@ "properties": {}, "type": "+" }, - "128": { + "126": { "connections": [ [ [ - 129, + 127, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_034", + "obj_state": 3, "position_x": 405.4444885253906, "position_y": 334.4338684082031, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, "width": 35 }, @@ -1014,84 +1313,79 @@ "properties": {}, "type": "*" }, - "129": { + "127": { "connections": [ [ [ - 130, + 128, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", - "no_export": false, - "position_x": 405.44451904296875, - "position_y": 374.4471740722656, - "scope": "__patch__", - "show_label": true, - "update_required": false, - "width": 36.0 - }, - "initargs": "3", - "midi_filters": null, - "midi_mode": null, - "name": "processor_035", - "osc_methods": [], - "properties": {}, - "type": "*" - }, - "13": { - "connections": [ - [] - ], - "do_onload": false, - "gui_params": { - "display_type": "text", - "height": 89.0, - "is_export": false, - "layername": "1. Command line", - "no_export": false, - "position_x": 58.97983169555664, - "position_y": 288.694580078125, - "scope": "", - "update_required": true, - "value": "Note especially the -v option, which copies all log messages to the console. \nThis may be helpful if a problem is causing MFP to crash and take log messages \nwith it. Usually, after startup all log messages will go to the \"Log\" tab below, but \nwill not be printed to stdout.", - "width": 546.0 + "no_export": false, + "obj_name": "processor_035", + "obj_state": 3, + "position_x": 405.44451904296875, + "position_y": 374.4471740722656, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 35 }, - "initargs": null, + "initargs": "3", "midi_filters": null, "midi_mode": null, - "name": "text_021", + "name": "processor_035", "osc_methods": [], "properties": {}, - "type": "text", - "value": "Note especially the -v option, which copies all log messages to the console. \nThis may be helpful if a problem is causing MFP to crash and take log messages \nwith it. Usually, after startup all log messages will go to the \"Log\" tab below, but \nwill not be printed to stdout." + "type": "*" }, - "130": { + "128": { "connections": [ [ [ - 133, + 131, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_036", + "obj_state": 3, "position_x": 405.4403991699219, "position_y": 411.25360107421875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, "width": 35 }, @@ -1103,28 +1397,39 @@ "properties": {}, "type": "+" }, - "131": { + "129": { "connections": [ [ [ - 132, + 130, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_037", + "obj_state": 3, "position_x": 180.75213623046875, "position_y": 324.56939697265625, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 172.0 + "width": 170.0 }, "initargs": "x: 3*x*x + 4*x +5", "midi_filters": null, @@ -1134,23 +1439,70 @@ "properties": {}, "type": "func" }, - "132": { + "13": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, + "is_export": false, + "layername": "4. File operations", + "no_export": false, + "obj_name": "text_004", + "obj_state": 3, + "position_x": 39.7034912109375, + "position_y": 28.57501220703125, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "File operations", + "width": 164.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_004", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "File operations" + }, + "130": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_038", + "obj_state": 3, "position_x": 180.75213623046875, "position_y": 372.56939697265625, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 160.0 + "width": 174.0 }, "initargs": "\"func says y=%s\"", "midi_filters": null, @@ -1160,23 +1512,34 @@ "properties": {}, "type": "print" }, - "133": { + "131": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "15. Pattern: Functions", "no_export": false, + "obj_name": "processor_039", + "obj_state": 3, "position_x": 405.4403991699219, "position_y": 459.25360107421875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 189.0 + "width": 207.0 }, "initargs": "\"dataflow says y=%s\"", "midi_filters": null, @@ -1192,44 +1555,26 @@ ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, - "is_export": false, - "layername": "4. File operations", - "no_export": false, - "position_x": 39.7034912109375, - "position_y": 28.57501220703125, - "scope": "", - "update_required": true, - "value": "File operations", - "width": 105.0 - }, - "initargs": null, - "midi_filters": null, - "midi_mode": null, - "name": "text_004", - "osc_methods": [], - "properties": {}, - "type": "text", - "value": "File operations" - }, - "15": { - "connections": [ - [] - ], - "do_onload": false, - "gui_params": { - "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_022", + "obj_state": 3, "position_x": 67.84106063842773, "position_y": 75.05355834960938, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "C-f, as we have seen, creates an empty new patch. ", - "width": 351.0 + "width": 371.0 }, "initargs": null, "midi_filters": null, @@ -1240,23 +1585,32 @@ "type": "text", "value": "C-f, as we have seen, creates an empty new patch. " }, - "16": { + "15": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 68.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 65.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_023", + "obj_state": 3, "position_x": 67.85282516479492, "position_y": 111.92745971679688, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "C-s saves the current patch. A prompt for a filename will appear at the bottom\nof the canvas. As of this release, MFP always saves the file into the process working directory \n(if running standalone) or the session data directory (if run from the NSM session manager).", - "width": 625.0 + "width": 667.0 }, "initargs": null, "midi_filters": null, @@ -1267,23 +1621,32 @@ "type": "text", "value": "C-s saves the current patch. A prompt for a filename will appear at the bottom\nof the canvas. As of this release, MFP always saves the file into the process working directory \n(if running standalone) or the session data directory (if run from the NSM session manager)." }, - "17": { + "16": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 89.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_024", + "obj_state": 3, "position_x": 70.89670944213867, "position_y": 311.03700256347656, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "C-o opens a previously-saved patch. A prompt for a filename will appear at \nthe bottom of the canvas. The file will be searched for on the patch path, which is \nthe process working directory or session data directory plus any directories specified with \nthe -p option at startup time. ", - "width": 593.0 + "width": 640.0 }, "initargs": null, "midi_filters": null, @@ -1294,23 +1657,32 @@ "type": "text", "value": "C-o opens a previously-saved patch. A prompt for a filename will appear at \nthe bottom of the canvas. The file will be searched for on the patch path, which is \nthe process working directory or session data directory plus any directories specified with \nthe -p option at startup time. " }, - "18": { + "17": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 47.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_025", + "obj_state": 3, "position_x": 102.87378692626953, "position_y": 186.0366973876953, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Select your working patch by C-PGDN and type C-s to save it. Type a filename\nand RET to complete the file save.", - "width": 549.0 + "width": 588.0 }, "initargs": null, "midi_filters": null, @@ -1321,23 +1693,32 @@ "type": "text", "value": "--> Select your working patch by C-PGDN and type C-s to save it. Type a filename\nand RET to complete the file save." }, - "19": { + "18": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_026", + "obj_state": 3, "position_x": 70.90933990478516, "position_y": 241.0341339111328, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "C-w closes the current patch. ", - "width": 212.0 + "width": 223.0 }, "initargs": null, "midi_filters": null, @@ -1348,77 +1729,104 @@ "type": "text", "value": "C-w closes the current patch. " }, - "2": { + "19": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, - "layername": "0. Introduction", + "layername": "4. File operations", "no_export": false, - "position_x": 35.56041717529297, - "position_y": 25.977832794189453, - "scope": "", + "obj_name": "text_027", + "obj_state": 3, + "position_x": 102.86031341552734, + "position_y": 277.0379943847656, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "MFP Tutorial", - "width": 92.0 + "value": "--> Select your just-saved working patch by C-PGDN and type C-w to close it.", + "width": 557.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_002", + "name": "text_027", "osc_methods": [], "properties": {}, "type": "text", - "value": "MFP Tutorial" + "value": "--> Select your just-saved working patch by C-PGDN and type C-w to close it." }, - "20": { + "2": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, - "layername": "4. File operations", + "layername": "0. Introduction", "no_export": false, - "position_x": 102.86031341552734, - "position_y": 277.0379943847656, - "scope": "", + "obj_name": "text_003", + "obj_state": 3, + "position_x": 370.79770278930664, + "position_y": 32.94720458984375, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "--> Select your just-saved working patch by C-PGDN and type C-w to close it.", - "width": 521.0 + "value": "A (hopefully) gentle introduction to patching in MFP\nand a temporary substitute for proper documentation", + "width": 387.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_027", + "name": "text_003", "osc_methods": [], "properties": {}, "type": "text", - "value": "--> Select your just-saved working patch by C-PGDN and type C-w to close it." + "value": "A (hopefully) gentle introduction to patching in MFP\nand a temporary substitute for proper documentation" }, - "21": { + "20": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "4. File operations", "no_export": false, + "obj_name": "text_028", + "obj_state": 3, "position_x": 103.86155700683594, "position_y": 409.27880859375, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Open your working patch again by C-o <filename> RET", - "width": 385.0 + "width": 423.0 }, "initargs": null, "midi_filters": null, @@ -1429,23 +1837,32 @@ "type": "text", "value": "--> Open your working patch again by C-o <filename> RET" }, - "22": { + "21": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_031", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Hello, World", - "width": 92.0 + "width": 142.0 }, "initargs": null, "midi_filters": null, @@ -1456,23 +1873,32 @@ "type": "text", "value": "Hello, World" }, - "23": { + "22": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 47.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_032", + "obj_state": 3, "position_x": 43.82478332519531, "position_y": 72.19137573242188, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "To build a simple patch, you need to know how to create the elements and \nhow to use Connection mode to hook them up. In your working patch:", - "width": 500.0 + "width": 536.0 }, "initargs": null, "midi_filters": null, @@ -1483,23 +1909,32 @@ "type": "text", "value": "To build a simple patch, you need to know how to create the elements and \nhow to use Connection mode to hook them up. In your working patch:" }, - "24": { + "23": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_033", + "obj_state": 3, "position_x": 59.90829086303711, "position_y": 129.77536010742188, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Type the following to create a message box:", - "width": 323.0 + "width": 345.0 }, "initargs": null, "midi_filters": null, @@ -1510,23 +1945,32 @@ "type": "text", "value": "--> Type the following to create a message box:" }, - "25": { + "24": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_034", + "obj_state": 3, "position_x": 86.8471908569336, "position_y": 156.15927124023438, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "m \"hello, world\" RET", - "width": 144.0 + "width": 157.0 }, "initargs": null, "midi_filters": null, @@ -1537,23 +1981,32 @@ "type": "text", "value": "m \"hello, world\" RET" }, - "26": { + "25": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 47.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_035", + "obj_state": 3, "position_x": 65.89913177490234, "position_y": 195.82044982910156, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Type the following to create a print processor:\n ap print RET", - "width": 335.0 + "width": 360.0 }, "initargs": null, "midi_filters": null, @@ -1564,23 +2017,32 @@ "type": "text", "value": "--> Type the following to create a print processor:\n ap print RET" }, - "27": { + "26": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_036", + "obj_state": 3, "position_x": 67.89301300048828, "position_y": 252.06478881835938, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Hit TAB to select the message box", - "width": 261.0 + "width": 277.0 }, "initargs": null, "midi_filters": null, @@ -1591,23 +2053,32 @@ "type": "text", "value": "--> Hit TAB to select the message box" }, - "28": { + "27": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 110.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 105.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_037", + "obj_state": 3, "position_x": 68.89801025390625, "position_y": 286.9288024902344, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Type the following to connect the message box to the print processor:\n c (to enter Connection mode with the message as the start of connection)\n TAB (to select the print processor as the other end of connection)\n RET (to create the connection)\n Your patch should look like the one to the right", - "width": 561.0 + "width": 593.0 }, "initargs": null, "midi_filters": null, @@ -1618,23 +2089,32 @@ "type": "text", "value": "--> Type the following to connect the message box to the print processor:\n c (to enter Connection mode with the message as the start of connection)\n TAB (to select the print processor as the other end of connection)\n RET (to create the connection)\n Your patch should look like the one to the right" }, - "29": { + "28": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 68.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 65.0, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "text_038", + "obj_state": 3, "position_x": 70.89775085449219, "position_y": 405.02801513671875, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "--> Hit ESC to enter Operate mode, then click on the message box\n\nObserve that the message \"hello, world\" appears in the log tab below. ", - "width": 471.0 + "width": 505.0 }, "initargs": null, "midi_filters": null, @@ -1645,80 +2125,107 @@ "type": "text", "value": "--> Hit ESC to enter Operate mode, then click on the message box\n\nObserve that the message \"hello, world\" appears in the log tab below. " }, - "3": { + "29": { "connections": [ - [] + [ + [ + 30, + 0 + ] + ] ], "do_onload": false, "gui_params": { - "display_type": "text", - "height": 47.0, + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, - "layername": "0. Introduction", + "layername": "5. Hello, world", "no_export": false, - "position_x": 370.79770278930664, - "position_y": 32.94720458984375, - "scope": "", + "obj_name": "message_001", + "obj_state": 3, + "position_x": 454.8407897949219, + "position_y": 167.82728576660156, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "A (hopefully) gentle introduction to patching in MFP\nand a temporary substitute for proper documentation", - "width": 355.0 + "width": 117.0 }, - "initargs": null, + "initargs": "\"hello, world\"", "midi_filters": null, "midi_mode": null, - "name": "text_003", + "name": "message_001", "osc_methods": [], "properties": {}, - "type": "text", - "value": "A (hopefully) gentle introduction to patching in MFP\nand a temporary substitute for proper documentation" + "type": "message" }, - "30": { + "3": { "connections": [ - [ - [ - 31, - 0 - ] - ] + [] ], "do_onload": false, "gui_params": { - "display_type": "message", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 245.0, "is_export": false, - "layername": "5. Hello, world", + "layername": "0. Introduction", "no_export": false, - "position_x": 454.8407897949219, - "position_y": 167.82728576660156, - "scope": "", + "obj_name": "text_005", + "obj_state": 3, + "position_x": 48.830509185791016, + "position_y": 155.14028930664062, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "width": 109.0 + "value": "This tutorial uses MFP \"layers\" as pages. You should see a list of them in the \"Layers\" tab \nto the left. To advance through the tutorial, you can either click on the desired page in the\nLayers tab, or use the Page Down/Page Up keys to move to the next/previous page. \n\nNote that some instructions in the tutorial will \"jump\" away from the tutorial, requiring\nyou to navigate back by clicking on the appropriate page in the Layers tab. Do not be \nalarmed. \n\nInstructions in italics with --> before them are your tutorial steps. \n\n--> Press the Page Down key now to get started. \n", + "width": 641.0 }, - "initargs": "\"hello, world\"", + "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "message_001", + "name": "text_005", "osc_methods": [], "properties": {}, - "type": "message" + "type": "text", + "value": "This tutorial uses MFP \"layers\" as pages. You should see a list of them in the \"Layers\" tab \nto the left. To advance through the tutorial, you can either click on the desired page in the\nLayers tab, or use the Page Down/Page Up keys to move to the next/previous page. \n\nNote that some instructions in the tutorial will \"jump\" away from the tutorial, requiring\nyou to navigate back by clicking on the appropriate page in the Layers tab. Do not be \nalarmed. \n\nInstructions in italics with --> before them are your tutorial steps. \n\n--> Press the Page Down key now to get started. \n" }, - "31": { + "30": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "5. Hello, world", "no_export": false, + "obj_name": "processor_001", + "obj_state": 3, "position_x": 454.841796875, "position_y": 215.8342742919922, - "scope": "", + "position_z": 0, + "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 44.0 + "width": 48.0 }, "initargs": null, "midi_filters": null, @@ -1728,23 +2235,32 @@ "properties": {}, "type": "print" }, - "32": { + "31": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_041", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Creating elements", - "width": 130.0 + "width": 201.0 }, "initargs": null, "midi_filters": null, @@ -1755,23 +2271,32 @@ "type": "text", "value": "Creating elements" }, - "33": { + "32": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 404.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 385.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_044", + "obj_state": 3, "position_x": 43.054805755615234, "position_y": 61.53874969482422, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "In the \"hello, world\" example you used m and p to create patch \nelements. All the keys to create elements are part of Patch Edit mode, and they are: \n\nBasics: \n m Create a message box\n p Create a processor (user patch or builtin with no special UI)\n n Create a number box\n t Create a text comment\n\nControls: \n u Create a toggle button \n g Create a \"bang\" (momentary) button \n s Create a slider\n d Create a dial (round slider)\n\nDisplay:\n b Create a bar meter\n i Create an indicator (on/off toggle display)\n x X/Y plot (oscilloscope or scatter style) ", - "width": 566.0 + "width": 599.0 }, "initargs": null, "midi_filters": null, @@ -1782,22 +2307,29 @@ "type": "text", "value": "In the \"hello, world\" example you used m and p to create patch \nelements. All the keys to create elements are part of Patch Edit mode, and they are: \n\nBasics: \n m Create a message box\n p Create a processor (user patch or builtin with no special UI)\n n Create a number box\n t Create a text comment\n\nControls: \n u Create a toggle button \n g Create a \"bang\" (momentary) button \n s Create a slider\n d Create a dial (round slider)\n\nDisplay:\n b Create a bar meter\n i Create an indicator (on/off toggle display)\n x X/Y plot (oscilloscope or scatter style) " }, - "34": { + "33": { "connections": [ [] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "message_002", + "obj_state": 3, "position_x": 506.82916259765625, "position_y": 128.84127807617188, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "width": 64.0 + "width": 68.0 }, "initargs": "\"hello\"", "midi_filters": null, @@ -1807,23 +2339,34 @@ "properties": {}, "type": "message" }, - "35": { + "34": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "processor_002", + "obj_state": 3, "position_x": 507.82879638671875, "position_y": 161.81533813476562, - "scope": "", + "position_z": 0, + "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 44.0 + "width": 48.0 }, "initargs": null, "midi_filters": null, @@ -1833,26 +2376,33 @@ "properties": {}, "type": "print" }, - "36": { + "35": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "digits": 1, "display_type": "enum", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "6. Creating elements", "max_value": null, "min_value": null, "no_export": false, + "obj_name": "enum_001", + "obj_state": 3, "position_x": 507.82879638671875, "position_y": 194.77142333984375, + "position_z": 0, "scientific": false, - "scope": "", + "scope": "__patch__", + "style": {}, "update_required": true, - "width": 42.0 + "width": 44.0 }, "initargs": "0.0", "midi_filters": null, @@ -1863,23 +2413,32 @@ "type": "enum", "value": 0.0 }, - "37": { + "36": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_045", + "obj_state": 3, "position_x": 588.8088989257812, "position_y": 129.85923767089844, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Message", - "width": 67.0 + "width": 71.0 }, "initargs": null, "midi_filters": null, @@ -1890,23 +2449,32 @@ "type": "text", "value": "Message" }, - "38": { + "37": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_046", + "obj_state": 3, "position_x": 589.8108520507812, "position_y": 164.81732177734375, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Processor", - "width": 74.0 + "width": 78.0 }, "initargs": null, "midi_filters": null, @@ -1917,23 +2485,32 @@ "type": "text", "value": "Processor" }, - "39": { + "38": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_047", + "obj_state": 3, "position_x": 589.8136596679688, "position_y": 196.79537963867188, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Number", - "width": 62.0 + "width": 68.0 }, "initargs": null, "midi_filters": null, @@ -1944,77 +2521,104 @@ "type": "text", "value": "Number" }, - "4": { + "39": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 257.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, - "layername": "0. Introduction", + "layername": "6. Creating elements", "no_export": false, - "position_x": 48.830509185791016, - "position_y": 155.14028930664062, - "scope": "", + "obj_name": "text_048", + "obj_state": 3, + "position_x": 507.83953857421875, + "position_y": 229.7684326171875, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "This tutorial uses MFP \"layers\" as pages. You should see a list of them in the \"Layers\" tab \nto the left. To advance through the tutorial, you can either click on the desired page in the\nLayers tab, or use the Page Down/Page Up keys to move to the next/previous page. \n\nNote that some instructions in the tutorial will \"jump\" away from the tutorial, requiring\nyou to navigate back by clicking on the appropriate page in the Layers tab. Do not be \nalarmed. \n\nInstructions in italics with --> before them are your tutorial steps. \n\n--> Press the Page Down key now to get started. \n", - "width": 598.0 + "value": "Hello!", + "width": 51.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_005", + "name": "text_048", "osc_methods": [], "properties": {}, "type": "text", - "value": "This tutorial uses MFP \"layers\" as pages. You should see a list of them in the \"Layers\" tab \nto the left. To advance through the tutorial, you can either click on the desired page in the\nLayers tab, or use the Page Down/Page Up keys to move to the next/previous page. \n\nNote that some instructions in the tutorial will \"jump\" away from the tutorial, requiring\nyou to navigate back by clicking on the appropriate page in the Layers tab. Do not be \nalarmed. \n\nInstructions in italics with --> before them are your tutorial steps. \n\n--> Press the Page Down key now to get started. \n" + "value": "Hello!" }, - "40": { + "4": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, - "layername": "6. Creating elements", + "layername": "0. Introduction", "no_export": false, - "position_x": 507.83953857421875, - "position_y": 229.7684326171875, - "scope": "", + "obj_name": "text_007", + "obj_state": 3, + "position_x": 46.9422492980957, + "position_y": 467.1565856933594, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "Hello!", - "width": 50.0 + "value": "Copyright © Bill Gribble <grib@billgribble.com>", + "width": 349.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_048", + "name": "text_007", "osc_methods": [], "properties": {}, "type": "text", - "value": "Hello!" + "value": "Copyright © Bill Gribble <grib@billgribble.com>" }, - "41": { + "40": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_049", + "obj_state": 3, "position_x": 587.8133544921875, "position_y": 228.77142333984375, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Comment", - "width": 74.0 + "width": 80.0 }, "initargs": null, "midi_filters": null, @@ -2025,22 +2629,30 @@ "type": "text", "value": "Comment" }, - "42": { + "41": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "toggle", + "export_offset_x": 0, + "export_offset_y": 0, "height": 20, "is_export": false, + "label_text": "", "layername": "6. Creating elements", "no_export": false, + "obj_name": "toggle_001", + "obj_state": 3, "off_message": false, "on_message": true, "position_x": 518.8341674804688, "position_y": 258.73150634765625, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "width": 20 }, @@ -2050,26 +2662,34 @@ "name": "toggle_001", "osc_methods": [], "properties": {}, - "type": "var", - "value": false + "type": "var" }, - "43": { + "42": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_050", + "obj_state": 3, "position_x": 589.8136596679688, "position_y": 259.7294921875, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Toggle", - "width": 54.0 + "width": 58.0 }, "initargs": null, "midi_filters": null, @@ -2080,23 +2700,29 @@ "type": "text", "value": "Toggle" }, - "44": { + "43": { "connections": [ [] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "button", + "export_offset_x": 0, + "export_offset_y": 0, "height": 20, "is_export": false, + "label_text": "", "layername": "6. Creating elements", - "message": { - "__BangType__": {} - }, + "message": null, "no_export": false, + "obj_name": "button_013", + "obj_state": 3, "position_x": 518.8341674804688, "position_y": 290.6846008300781, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "width": 20 }, @@ -2106,26 +2732,34 @@ "name": "button_013", "osc_methods": [], "properties": {}, - "type": "var", - "value": false + "type": "var" }, - "45": { + "44": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_051", + "obj_state": 3, "position_x": 590.8133544921875, "position_y": 290.67962646484375, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Bang", - "width": 42.0 + "width": 46.0 }, "initargs": null, "midi_filters": null, @@ -2136,26 +2770,34 @@ "type": "text", "value": "Bang" }, - "46": { + "45": { "connections": [ [] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "slidemeter", + "export_offset_x": 0, + "export_offset_y": 0, "height": 25, "is_export": false, "layername": "6. Creating elements", "max_value": 1.0, "min_value": 0.0, "no_export": false, - "orientation": 1, + "obj_name": "slidemeter_001", + "obj_state": 3, + "orientation": 0, "position_x": 478.8487548828125, "position_y": 324.6755676269531, + "position_z": 0, + "scale": null, + "scale_font_size": 7, "scale_position": 0, - "scale_type": 0, - "scope": "", + "scope": "__patch__", "show_scale": false, + "style": {}, "update_required": true, "width": 100, "zeropoint": null @@ -2169,23 +2811,32 @@ "type": "slidemeter", "value": 0.0 }, - "47": { + "46": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_052", + "obj_state": 3, "position_x": 589.812744140625, "position_y": 325.67462158203125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Slider", - "width": 47.0 + "width": 50.0 }, "initargs": null, "midi_filters": null, @@ -2196,27 +2847,35 @@ "type": "text", "value": "Slider" }, - "48": { + "47": { "connections": [ [] ], "do_onload": false, "gui_params": { + "debug": false, "dial_radius": 24, "display_type": "dial", + "export_offset_x": 0, + "export_offset_y": 0, "height": 50, "is_export": false, "layername": "6. Creating elements", "max_value": 1.0, "min_value": 0.0, "no_export": false, + "obj_name": "dial_001", + "obj_state": 3, "orientation": 0, "position_x": 501.83795166015625, "position_y": 359.6197204589844, + "position_z": 0, + "scale": null, + "scale_font_size": 7, "scale_position": 0, - "scale_type": 0, - "scope": "", + "scope": "__patch__", "show_scale": false, + "style": {}, "update_required": true, "width": 50, "zeropoint": null @@ -2230,23 +2889,32 @@ "type": "slidemeter", "value": 0.0 }, - "49": { + "48": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, "layername": "6. Creating elements", "no_export": false, + "obj_name": "text_053", + "obj_state": 3, "position_x": 590.812744140625, "position_y": 369.6336975097656, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Dial", - "width": 34.0 + "width": 37.0 }, "initargs": null, "midi_filters": null, @@ -2257,77 +2925,104 @@ "type": "text", "value": "Dial" }, - "5": { + "49": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, - "layername": "0. Introduction", + "layername": "3. Edit and Operate", "no_export": false, - "position_x": 46.9422492980957, - "position_y": 467.1565856933594, - "scope": "", + "obj_name": "text_006", + "obj_state": 3, + "position_x": 37.627967834472656, + "position_y": 26.559978485107422, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "Copyright © 2010-2014 Bill Gribble <grib@billgribble.com>", - "width": 400.0 + "value": "Edit and Operate modes", + "width": 260.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_007", + "name": "text_006", "osc_methods": [], "properties": {}, "type": "text", - "value": "Copyright © 2010-2014 Bill Gribble <grib@billgribble.com>" + "value": "Edit and Operate modes" }, - "50": { + "5": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25.0, "is_export": false, - "layername": "3. Edit and Operate", + "layername": "0. Introduction", "no_export": false, - "position_x": 37.627967834472656, - "position_y": 26.559978485107422, + "obj_name": "text_010", + "obj_state": 3, + "position_x": 49.98160171508789, + "position_y": 401.56463623046875, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "value": "Edit and Operate modes", - "width": 166.0 + "value": "If you are here by mistake, or are bored, type C-q (control-q) to quit. ", + "width": 492.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_006", + "name": "text_010", "osc_methods": [], "properties": {}, "type": "text", - "value": "Edit and Operate modes" + "value": "If you are here by mistake, or are bored, type C-q (control-q) to quit. " }, - "51": { + "50": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 341.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 325.0, "is_export": false, "layername": "3. Edit and Operate", "no_export": false, + "obj_name": "text_042", + "obj_state": 3, "position_x": 70.83895111083984, "position_y": 81.22675323486328, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "In the lower right corner of the canvas, find the mode indicator. It will say either \nEdit or Operate. This is the \"major mode\" that MFP uses to interpret \nyour key presses and mouse activity. \n\nEdit mode allows you to create, move, and edit objects in the patch. Your key\npresses and mouse activity are interpreted as editing operations. MFP starts in Edit\nmode. To re-enter Edit mode, type C-SPC (control-space). \n\nOperate mode allows you to operate the patch. Your inputs are interpreted as\ncontrol operations, and will not alter the patch. You need to be in Operate mode \nto click buttons or messages, drag sliders, etc. To enter Operate mode, hit \nESC (escape). \n\n--> Hit ESC to enter Operate mode. Note the change in the Mode Indicator\n\n--> Hit C-SPC to return to Edit mode.", - "width": 551.0 + "width": 596.0 }, "initargs": null, "midi_filters": null, @@ -2338,23 +3033,32 @@ "type": "text", "value": "In the lower right corner of the canvas, find the mode indicator. It will say either \nEdit or Operate. This is the \"major mode\" that MFP uses to interpret \nyour key presses and mouse activity. \n\nEdit mode allows you to create, move, and edit objects in the patch. Your key\npresses and mouse activity are interpreted as editing operations. MFP starts in Edit\nmode. To re-enter Edit mode, type C-SPC (control-space). \n\nOperate mode allows you to operate the patch. Your inputs are interpreted as\ncontrol operations, and will not alter the patch. You need to be in Operate mode \nto click buttons or messages, drag sliders, etc. To enter Operate mode, hit \nESC (escape). \n\n--> Hit ESC to enter Operate mode. Note the change in the Mode Indicator\n\n--> Hit C-SPC to return to Edit mode." }, - "52": { + "51": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "7. Zoom and scroll", "no_export": false, + "obj_name": "text_008", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Zoom and Scroll", - "width": 114.0 + "width": 180.0 }, "initargs": null, "midi_filters": null, @@ -2365,23 +3069,32 @@ "type": "text", "value": "Zoom and Scroll" }, - "53": { + "52": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 320.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 305.0, "is_export": false, "layername": "7. Zoom and scroll", "no_export": false, + "obj_name": "text_043", + "obj_state": 3, "position_x": 66.5006103515625, "position_y": 88.23711395263672, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "Zoom and scroll on the canvas are handled without scrollbars, using a \"drag\nto scroll and scroll to zoom\" model something like Google Maps. \n\nC-S-M1MOTION is the keybinding to drag the canvas. That is, hold \ndown the Control and Shift keys while clicking mouse button 1 (usually left) \nand dragging. \n\n --> Use C-S-M1MOTION to drag the canvas around. \n\nThe scroll wheel zooms in and out.\n\n --> Zoom! \n\nC-0 (control-zero) resets the zoom to 1, and the position of the canvas \nto its starting point. ", - "width": 510.0 + "width": 542.0 }, "initargs": null, "midi_filters": null, @@ -2392,23 +3105,32 @@ "type": "text", "value": "Zoom and scroll on the canvas are handled without scrollbars, using a \"drag\nto scroll and scroll to zoom\" model something like Google Maps. \n\nC-S-M1MOTION is the keybinding to drag the canvas. That is, hold \ndown the Control and Shift keys while clicking mouse button 1 (usually left) \nand dragging. \n\n --> Use C-S-M1MOTION to drag the canvas around. \n\nThe scroll wheel zooms in and out.\n\n --> Zoom! \n\nC-0 (control-zero) resets the zoom to 1, and the position of the canvas \nto its starting point. " }, - "54": { + "53": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "text_009", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Sequencing", - "width": 142.0 + "width": 218.0 }, "initargs": null, "midi_filters": null, @@ -2419,23 +3141,32 @@ "type": "text", "value": "Pattern: Sequencing" }, - "55": { + "54": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 89.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "text_012", + "obj_state": 3, "position_x": 65.81330871582031, "position_y": 76.09557342529297, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "Think of a patch as a graph where messages are passed between nodes \ndepth first and outputs of a processor (generally) occur \nin right to left order. The [trigger] object does nothing \nexcept repeat its input to multiple outputs in right-to-left order.", - "width": 476.0 + "width": 511.0 }, "initargs": null, "midi_filters": null, @@ -2446,27 +3177,34 @@ "type": "text", "value": "Think of a patch as a graph where messages are passed between nodes \ndepth first and outputs of a processor (generally) occur \nin right to left order. The [trigger] object does nothing \nexcept repeat its input to multiple outputs in right-to-left order." }, - "56": { + "55": { "connections": [ [ [ - 57, + 56, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "message_003", + "obj_state": 3, "position_x": 170.74330139160156, "position_y": 179.89581298828125, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 64.0 + "width": 68.0 }, "initargs": "\"hello\"", "midi_filters": null, @@ -2476,40 +3214,51 @@ "properties": {}, "type": "message" }, - "57": { + "56": { "connections": [ [ [ - 58, + 57, 0 ] ], [ [ - 59, + 58, 0 ] ], [ [ - 60, + 59, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "processor_003", + "obj_state": 3, "position_x": 170.74330139160156, "position_y": 227.89581298828125, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 70.0 + "width": 75.0 }, "initargs": "3", "midi_filters": null, @@ -2519,23 +3268,34 @@ "properties": {}, "type": "trigger" }, - "58": { + "57": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "processor_005", + "obj_state": 3, "position_x": 170.74330139160156, "position_y": 265.89581298828125, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 73.0 + "width": 79.0 }, "initargs": "\"3:\"", "midi_filters": null, @@ -2545,23 +3305,34 @@ "properties": {}, "type": "print" }, - "59": { + "58": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "processor_006", + "obj_state": 3, "position_x": 200.70127868652344, "position_y": 298.9131774902344, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 73.0 + "width": 78.0 }, "initargs": "\"2:\"", "midi_filters": null, @@ -2571,76 +3342,105 @@ "properties": {}, "type": "print" }, - "6": { + "59": { "connections": [ [] ], - "do_onload": false, + "do_onload": true, "gui_params": { - "display_type": "text", - "height": 26.0, + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, - "layername": "0. Introduction", + "layername": "9. Pattern: Sequencing", "no_export": false, - "position_x": 49.98160171508789, - "position_y": 401.56463623046875, - "scope": "", - "update_required": true, - "value": "If you are here by mistake, or are bored, type C-q (control-q) to quit. ", - "width": 459.0 + "obj_name": "processor_007", + "obj_state": 3, + "position_x": 231.74330139160156, + "position_y": 335.89581298828125, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 77.0 }, - "initargs": null, + "initargs": "\"1:\"", "midi_filters": null, "midi_mode": null, - "name": "text_010", + "name": "processor_007", "osc_methods": [], "properties": {}, - "type": "text", - "value": "If you are here by mistake, or are bored, type C-q (control-q) to quit. " + "type": "print" }, - "60": { + "6": { "connections": [ [] ], - "do_onload": true, + "do_onload": false, "gui_params": { - "display_type": "processor", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, - "layername": "9. Pattern: Sequencing", + "layername": "2. Creating a patch", "no_export": false, - "position_x": 231.74330139160156, - "position_y": 335.89581298828125, + "obj_name": "text_011", + "obj_state": 3, + "position_x": 39.7034912109375, + "position_y": 28.57501220703125, + "position_z": 0, "scope": "__patch__", - "show_label": true, - "update_required": false, - "width": 73.0 + "style": {}, + "update_required": true, + "value": "Creating a patch", + "width": 179.0 }, - "initargs": "\"1:\"", + "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "processor_007", + "name": "text_011", "osc_methods": [], "properties": {}, - "type": "print" + "type": "text", + "value": "Creating a patch" }, - "61": { + "60": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 47.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, "layername": "9. Pattern: Sequencing", "no_export": false, + "obj_name": "text_013", + "obj_state": 3, "position_x": 63.903926849365234, "position_y": 385.02447509765625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "This is the essential pattern to use when you need to execute steps \nin a certain order.", - "width": 458.0 + "width": 482.0 }, "initargs": null, "midi_filters": null, @@ -2651,23 +3451,32 @@ "type": "text", "value": "This is the essential pattern to use when you need to execute steps \nin a certain order." }, - "62": { + "61": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "text_016", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Hot and Cold", - "width": 96.0 + "width": 145.0 }, "initargs": null, "midi_filters": null, @@ -2678,23 +3487,32 @@ "type": "text", "value": "Hot and Cold" }, - "63": { + "62": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 68.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 65.0, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "text_017", + "obj_state": 3, "position_x": 65.73871612548828, "position_y": 80.26740264892578, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "Data coming into a processor only trigger the processor if the inlet is \"hot\". Usually,\nonly the leftmost inlet is \"hot\". To marshal a set of inputs (arguments) to the \nprocessor, send to all the other inlets first, then to the leftmost inlet.", - "width": 552.0 + "width": 595.0 }, "initargs": null, "midi_filters": null, @@ -2705,23 +3523,32 @@ "type": "text", "value": "Data coming into a processor only trigger the processor if the inlet is \"hot\". Usually,\nonly the leftmost inlet is \"hot\". To marshal a set of inputs (arguments) to the \nprocessor, send to all the other inlets first, then to the leftmost inlet." }, - "64": { + "63": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 47.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 45.0, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "text_029", + "obj_state": 3, "position_x": 67.91510009765625, "position_y": 165.6861572265625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "In the example below, [pack] builds a Python array from its inputs. \nClick in different orders and see what comes out and when it comes out. ", - "width": 488.0 + "width": 523.0 }, "initargs": null, "midi_filters": null, @@ -2732,27 +3559,34 @@ "type": "text", "value": "In the example below, [pack] builds a Python array from its inputs. \nClick in different orders and see what comes out and when it comes out. " }, - "65": { + "64": { "connections": [ [ [ - 69, + 68, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "message_004", + "obj_state": 3, "position_x": 148.82178497314453, "position_y": 270.15228271484375, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 64.0 + "width": 68.0 }, "initargs": "\"hello\"", "midi_filters": null, @@ -2762,27 +3596,34 @@ "properties": {}, "type": "message" }, - "66": { + "65": { "connections": [ [ [ - 69, + 68, 1 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "message_005", + "obj_state": 3, "position_x": 231.72256469726562, "position_y": 267.80377197265625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 69.0 + "width": 67.0 }, "initargs": "123.45", "midi_filters": null, @@ -2792,27 +3633,34 @@ "properties": {}, "type": "message" }, - "67": { + "66": { "connections": [ [ [ - 69, + 68, 2 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "message_006", + "obj_state": 3, "position_x": 318.6184844970703, "position_y": 264.6605224609375, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 65.0 + "width": 64.0 }, "initargs": "[1,2,3]", "midi_filters": null, @@ -2822,27 +3670,34 @@ "properties": {}, "type": "message" }, - "68": { + "67": { "connections": [ [ [ - 69, + 68, 3 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "message_007", + "obj_state": 3, "position_x": 403.51683044433594, "position_y": 265.2290802001953, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 49.0 + "width": 52.0 }, "initargs": "True", "midi_filters": null, @@ -2852,28 +3707,39 @@ "properties": {}, "type": "message" }, - "69": { + "68": { "connections": [ [ [ - 70, + 69, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "8. Hot and Cold", "no_export": false, + "obj_name": "processor_008", + "obj_state": 3, "position_x": 250.69983673095703, "position_y": 330.7385559082031, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 56.0 + "width": 60.0 }, "initargs": "4", "midi_filters": null, @@ -2883,76 +3749,105 @@ "properties": {}, "type": "pack" }, - "7": { + "69": { "connections": [ [] ], - "do_onload": false, + "do_onload": true, "gui_params": { - "display_type": "text", - "height": 26.0, + "debug": false, + "display_type": "processor", + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, - "layername": "2. Creating a patch", + "layername": "8. Hot and Cold", "no_export": false, - "position_x": 39.7034912109375, - "position_y": 28.57501220703125, - "scope": "", - "update_required": true, - "value": "Creating a patch", - "width": 116.0 + "obj_name": "processor_009", + "obj_state": 3, + "position_x": 250.69983673095703, + "position_y": 382.7312316894531, + "position_z": 0, + "scope": "__patch__", + "show_label": true, + "style": {}, + "update_required": false, + "width": 48.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_011", + "name": "processor_009", "osc_methods": [], "properties": {}, - "type": "text", - "value": "Creating a patch" + "type": "print" }, - "70": { + "7": { "connections": [ [] ], - "do_onload": true, + "do_onload": false, "gui_params": { - "display_type": "processor", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, "is_export": false, - "layername": "8. Hot and Cold", + "layername": "2. Creating a patch", "no_export": false, - "position_x": 250.69983673095703, - "position_y": 382.7312316894531, + "obj_name": "text_014", + "obj_state": 3, + "position_x": 62.976043701171875, + "position_y": 83.92110443115234, + "position_z": 0, "scope": "__patch__", - "show_label": true, - "update_required": false, - "width": 44.0 + "style": {}, + "update_required": true, + "value": "To work through the rest of this tutorial, it will be helpful to have an empty patch\nto work with. If you click on the \"Keybindings\" tab to the left and scroll down a bit, \nyou will see the entry \"C-f Create a new patch\". C-f means Control-f. Similarly, A- \nmeans Alt, S- means Shift, W- means the Windows key, M1 means first mouse button. ", + "width": 624.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "processor_009", + "name": "text_014", "osc_methods": [], "properties": {}, - "type": "print" + "type": "text", + "value": "To work through the rest of this tutorial, it will be helpful to have an empty patch\nto work with. If you click on the \"Keybindings\" tab to the left and scroll down a bit, \nyou will see the entry \"C-f Create a new patch\". C-f means Control-f. Similarly, A- \nmeans Alt, S- means Shift, W- means the Windows key, M1 means first mouse button. " }, - "71": { + "70": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "text_030", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Iteration", - "width": 122.0 + "width": 189.0 }, "initargs": null, "midi_filters": null, @@ -2963,23 +3858,32 @@ "type": "text", "value": "Pattern: Iteration" }, - "72": { + "71": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 173.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 165.0, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "text_039", + "obj_state": 3, "position_x": 62.799190521240234, "position_y": 82.15888214111328, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "The [for] object is key to iteration. It splits a list of inputs into \nits elements and outputs them one at a time. The items to iterate over \ncan be either init args (in the processor box) or received either inlet.\n\nIteration starts when a Bang, True, or an iterable is received on the left (hot) inlet.\n\nIteration will stop when the current list is traversed or a False is receved on\nthe left inlet. ", - "width": 542.0 + "width": 580.0 }, "initargs": null, "midi_filters": null, @@ -2990,27 +3894,34 @@ "type": "text", "value": "The [for] object is key to iteration. It splits a list of inputs into \nits elements and outputs them one at a time. The items to iterate over \ncan be either init args (in the processor box) or received either inlet.\n\nIteration starts when a Bang, True, or an iterable is received on the left (hot) inlet.\n\nIteration will stop when the current list is traversed or a False is receved on\nthe left inlet. " }, - "73": { + "72": { "connections": [ [ [ - 74, + 73, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "message_008", + "obj_state": 3, "position_x": 127.87886810302734, "position_y": 271.86598205566406, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 52.0 + "width": 56.0 }, "initargs": "Bang", "midi_filters": null, @@ -3020,28 +3931,39 @@ "properties": {}, "type": "message" }, - "74": { + "73": { "connections": [ [ [ - 75, + 74, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "processor_004", + "obj_state": 3, "position_x": 192.7921371459961, "position_y": 345.80487060546875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 113.0 + "width": 118.0 }, "initargs": "range(3,10)", "midi_filters": null, @@ -3051,23 +3973,34 @@ "properties": {}, "type": "for" }, - "75": { + "74": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "processor_010", + "obj_state": 3, "position_x": 192.7921371459961, "position_y": 393.80487060546875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 44.0 + "width": 48.0 }, "initargs": null, "midi_filters": null, @@ -3077,27 +4010,34 @@ "properties": {}, "type": "print" }, - "76": { + "75": { "connections": [ [ [ - 74, + 73, 1 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "message_009", + "obj_state": 3, "position_x": 329.6121368408203, "position_y": 276.49725341796875, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 231.0 + "width": 253.0 }, "initargs": "[\"hello\", \"goodbye\", \"foo\", \"bar\"]", "midi_filters": null, @@ -3107,25 +4047,32 @@ "properties": {}, "type": "message" }, - "77": { + "76": { "connections": [ [ [ - 74, + 73, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "10. Pattern: Iteration", "no_export": false, + "obj_name": "message_010", + "obj_state": 3, "position_x": 215.77423095703125, "position_y": 274.49891662597656, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "width": 91.0 }, @@ -3137,23 +4084,32 @@ "properties": {}, "type": "message" }, - "78": { + "77": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "text_040", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Conditionals 1", - "width": 160.0 + "width": 245.0 }, "initargs": null, "midi_filters": null, @@ -3164,23 +4120,32 @@ "type": "text", "value": "Pattern: Conditionals 1" }, - "79": { + "78": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 89.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "text_054", + "obj_state": 3, "position_x": 55.8459358215332, "position_y": 66.17697143554688, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, "value": "The [case] and [route] objects are the building blocks of \nconditional code. [case] tests its left inlet for equality against a \nseries of values and repeats the input value on the corresponding positional \noutput. If no test matches, the value is repeated on the rightmost outlet. ", - "width": 502.0 + "width": 542.0 }, "initargs": null, "midi_filters": null, @@ -3191,84 +4156,107 @@ "type": "text", "value": "The [case] and [route] objects are the building blocks of \nconditional code. [case] tests its left inlet for equality against a \nseries of values and repeats the input value on the corresponding positional \noutput. If no test matches, the value is repeated on the rightmost outlet. " }, - "8": { + "79": { "connections": [ - [] + [ + [ + 83, + 0 + ] + ] ], "do_onload": false, "gui_params": { - "display_type": "text", - "height": 89.0, + "debug": false, + "display_type": "message", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, - "layername": "2. Creating a patch", + "layername": "11. Pattern: Conditionals 1", "no_export": false, - "position_x": 62.976043701171875, - "position_y": 83.92110443115234, - "scope": "", + "obj_name": "message_011", + "obj_state": 3, + "position_x": 62.90447998046875, + "position_y": 171.78334045410156, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "To work through the rest of this tutorial, it will be helpful to have an empty patch\nto work with. If you click on the \"Keybindings\" tab to the left and scroll down a bit, \nyou will see the entry \"C-f Create a new patch\". C-f means Control-f. Similarly, A- \nmeans Alt, S- means Shift, W- means the Windows key, M1 means first mouse button. ", - "width": 581.0 + "width": 52.0 }, - "initargs": null, + "initargs": "True", "midi_filters": null, "midi_mode": null, - "name": "text_014", + "name": "message_011", "osc_methods": [], "properties": {}, - "type": "text", - "value": "To work through the rest of this tutorial, it will be helpful to have an empty patch\nto work with. If you click on the \"Keybindings\" tab to the left and scroll down a bit, \nyou will see the entry \"C-f Create a new patch\". C-f means Control-f. Similarly, A- \nmeans Alt, S- means Shift, W- means the Windows key, M1 means first mouse button. " + "type": "message" }, - "80": { + "8": { "connections": [ - [ - [ - 84, - 0 - ] - ] + [] ], "do_onload": false, "gui_params": { - "display_type": "message", - "height": 25.0, + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 245.0, "is_export": false, - "layername": "11. Pattern: Conditionals 1", + "layername": "2. Creating a patch", "no_export": false, - "position_x": 62.90447998046875, - "position_y": 171.78334045410156, + "obj_name": "text_015", + "obj_state": 3, + "position_x": 61.95268249511719, + "position_y": 186.816650390625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 49.0 + "value": "--> Type C-f now to create a new patch. \n\nThis will only work if your pointer is over the \"canvas\", the main patch area where \nthis text appears. Observe that a message appears at the bottom of the canvas, then \nfades out after a few seconds, to let you know that this action was taken. \n\nClick on the Layers tab to see that there's a new top-level item called \"default\". This is \nyour working patch.\n\nThe PGUP and PGDN keys only cycle through layers in the current patch; to cycle \nthrough patches, C-PGUP and C-PGDN. You can also click on a layer of the other \npatch in the Layers tab.", + "width": 619.0 }, - "initargs": "True", + "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "message_011", + "name": "text_015", "osc_methods": [], "properties": {}, - "type": "message" + "type": "text", + "value": "--> Type C-f now to create a new patch. \n\nThis will only work if your pointer is over the \"canvas\", the main patch area where \nthis text appears. Observe that a message appears at the bottom of the canvas, then \nfades out after a few seconds, to let you know that this action was taken. \n\nClick on the Layers tab to see that there's a new top-level item called \"default\". This is \nyour working patch.\n\nThe PGUP and PGDN keys only cycle through layers in the current patch; to cycle \nthrough patches, C-PGUP and C-PGDN. You can also click on a layer of the other \npatch in the Layers tab." }, - "81": { + "80": { "connections": [ [ [ - 84, + 83, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "message_012", + "obj_state": 3, "position_x": 128.8043975830078, "position_y": 175.2103729248047, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 54.0 + "width": 56.0 }, "initargs": "False", "midi_filters": null, @@ -3278,27 +4266,34 @@ "properties": {}, "type": "message" }, - "82": { + "81": { "connections": [ [ [ - 84, + 83, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "message_013", + "obj_state": 3, "position_x": 198.69825744628906, "position_y": 174.77963256835938, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 64.0 + "width": 68.0 }, "initargs": "\"hello\"", "midi_filters": null, @@ -3308,27 +4303,34 @@ "properties": {}, "type": "message" }, - "83": { + "82": { "connections": [ [ [ - 84, + 83, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "message_014", + "obj_state": 3, "position_x": 276.5798645019531, "position_y": 176.2264862060547, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 88.0 + "width": 95.0 }, "initargs": "\"goodbye\"", "midi_filters": null, @@ -3338,46 +4340,57 @@ "properties": {}, "type": "message" }, - "84": { + "83": { "connections": [ [ [ - 88, + 87, 0 ] ], [ [ - 85, + 84, 0 ] ], [ [ - 86, + 85, 0 ] ], [ [ - 87, + 86, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "processor_011", + "obj_state": 3, "position_x": 98.849853515625, "position_y": 265.6834716796875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 170.0 + "width": 180.0 }, "initargs": "True, False, \"hello\"", "midi_filters": null, @@ -3387,23 +4400,34 @@ "properties": {}, "type": "case" }, - "85": { + "84": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "processor_013", + "obj_state": 3, "position_x": 151.7755584716797, "position_y": 338.682861328125, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 138.0 + "width": 148.0 }, "initargs": "\"it was false:\"", "midi_filters": null, @@ -3413,23 +4437,34 @@ "properties": {}, "type": "print" }, - "86": { + "85": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "processor_014", + "obj_state": 3, "position_x": 205.69515991210938, "position_y": 371.6820068359375, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 139.0 + "width": 150.0 }, "initargs": "\"it was hello:\"", "midi_filters": null, @@ -3439,23 +4474,34 @@ "properties": {}, "type": "print" }, - "87": { + "86": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "processor_015", + "obj_state": 3, "position_x": 259.61932373046875, "position_y": 404.4490051269531, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 206.0 + "width": 222.0 }, "initargs": "\"it was something else:\"", "midi_filters": null, @@ -3465,23 +4511,34 @@ "properties": {}, "type": "print" }, - "88": { + "87": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "11. Pattern: Conditionals 1", "no_export": false, + "obj_name": "processor_012", + "obj_state": 3, "position_x": 98.849853515625, "position_y": 303.6834716796875, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 134.0 + "width": 145.0 }, "initargs": "\"it was true:\"", "midi_filters": null, @@ -3491,23 +4548,32 @@ "properties": {}, "type": "print" }, - "89": { + "88": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "text_055", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Conditionals 2", - "width": 160.0 + "width": 248.0 }, "initargs": null, "midi_filters": null, @@ -3518,81 +4584,106 @@ "type": "text", "value": "Pattern: Conditionals 2" }, - "9": { + "89": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 257.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 65.0, "is_export": false, - "layername": "2. Creating a patch", + "layername": "12. Pattern: Conditionals 2", "no_export": false, - "position_x": 61.95268249511719, - "position_y": 186.816650390625, - "scope": "", + "obj_name": "text_056", + "obj_state": 3, + "position_x": 52.8647575378418, + "position_y": 83.16792297363281, + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, - "value": "--> Type C-f now to create a new patch. \n\nThis will only work if your pointer is over the \"canvas\", the main patch area where \nthis text appears. Observe that a message appears at the bottom of the canvas, then \nfades out after a few seconds, to let you know that this action was taken. \n\nClick on the Layers tab to see that there's a new top-level item called \"default\". This is \nyour working patch.\n\nThe PGUP and PGDN keys only cycle through layers in the current patch; to cycle \nthrough patches, C-PGUP and C-PGDN. You can also click on a layer of the other \npatch in the Layers tab.", - "width": 582.0 + "value": "[route] interprets input as a sequence where the first element is\nthe \"address\" that the rest of the sequence is to be delivered to. Items with\nunmatched addresses are passed through whole. ", + "width": 539.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_015", + "name": "text_056", "osc_methods": [], "properties": {}, "type": "text", - "value": "--> Type C-f now to create a new patch. \n\nThis will only work if your pointer is over the \"canvas\", the main patch area where \nthis text appears. Observe that a message appears at the bottom of the canvas, then \nfades out after a few seconds, to let you know that this action was taken. \n\nClick on the Layers tab to see that there's a new top-level item called \"default\". This is \nyour working patch.\n\nThe PGUP and PGDN keys only cycle through layers in the current patch; to cycle \nthrough patches, C-PGUP and C-PGDN. You can also click on a layer of the other \npatch in the Layers tab." + "value": "[route] interprets input as a sequence where the first element is\nthe \"address\" that the rest of the sequence is to be delivered to. Items with\nunmatched addresses are passed through whole. " }, - "90": { + "9": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 68.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 185.0, "is_export": false, - "layername": "12. Pattern: Conditionals 2", + "layername": "1. Command line", "no_export": false, - "position_x": 52.8647575378418, - "position_y": 83.16792297363281, + "obj_name": "text_018", + "obj_state": 3, + "position_x": 57.91237258911133, + "position_y": 80.91848754882812, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "value": "[route] interprets input as a sequence where the first element is\nthe \"address\" that the rest of the sequence is to be delivered to. Items with\nunmatched addresses are passed through whole. ", - "width": 509.0 + "value": "You have gotten this far, which is good news! You know how to open a patch file. \nIn case you forgot already: \n mfp [options] [filename ...] \n\nTo see a complete list of command-line options:\n mfp --help\n\nTo see a list of all builtin objects with a brief description: \n mfp --help-builtins", + "width": 591.0 }, "initargs": null, "midi_filters": null, "midi_mode": null, - "name": "text_056", + "name": "text_018", "osc_methods": [], "properties": {}, "type": "text", - "value": "[route] interprets input as a sequence where the first element is\nthe \"address\" that the rest of the sequence is to be delivered to. Items with\nunmatched addresses are passed through whole. " + "value": "You have gotten this far, which is good news! You know how to open a patch file. \nIn case you forgot already: \n mfp [options] [filename ...] \n\nTo see a complete list of command-line options:\n mfp --help\n\nTo see a list of all builtin objects with a brief description: \n mfp --help-builtins" }, - "91": { + "90": { "connections": [ [ [ - 94, + 93, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "message_015", + "obj_state": 3, "position_x": 108.83223342895508, "position_y": 177.79473876953125, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 91.0 + "width": 94.0 }, "initargs": "(2, \"hello\")", "midi_filters": null, @@ -3602,27 +4693,34 @@ "properties": {}, "type": "message" }, - "92": { + "91": { "connections": [ [ [ - 94, + 93, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "message_016", + "obj_state": 3, "position_x": 226.650634765625, "position_y": 184.2687530517578, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 114.0 + "width": 115.0 }, "initargs": "(\"foo\", 1, 2, 3)", "midi_filters": null, @@ -3632,27 +4730,34 @@ "properties": {}, "type": "message" }, - "93": { + "92": { "connections": [ [ [ - 94, + 93, 0 ] ] ], "do_onload": false, "gui_params": { + "debug": false, "display_type": "message", - "height": 25.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "message_017", + "obj_state": 3, "position_x": 371.427490234375, "position_y": 187.7554931640625, + "position_z": 0, "scope": "__patch__", + "style": {}, "update_required": true, - "width": 79.0 + "width": 87.0 }, "initargs": "[\"bar\", 4]", "midi_filters": null, @@ -3662,46 +4767,57 @@ "properties": {}, "type": "message" }, - "94": { + "93": { "connections": [ [ [ - 95, + 94, 0 ] ], [ [ - 96, + 95, 0 ] ], [ [ - 97, + 96, 0 ] ], [ [ - 98, + 97, 0 ] ] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "processor_016", + "obj_state": 3, "position_x": 135.79067993164062, "position_y": 251.06820678710938, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 120.0 + "width": 124.0 }, "initargs": "1, 2, \"foo\"", "midi_filters": null, @@ -3711,23 +4827,34 @@ "properties": {}, "type": "route" }, - "95": { + "94": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "processor_017", + "obj_state": 3, "position_x": 135.79067993164062, "position_y": 299.0682067871094, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 116.0 + "width": 123.0 }, "initargs": "\"it was 1:\"", "midi_filters": null, @@ -3737,23 +4864,34 @@ "properties": {}, "type": "print" }, - "96": { + "95": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "processor_018", + "obj_state": 3, "position_x": 171.79067993164062, "position_y": 329.0682067871094, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 116.0 + "width": 124.0 }, "initargs": "\"it was 2:\"", "midi_filters": null, @@ -3763,23 +4901,34 @@ "properties": {}, "type": "print" }, - "97": { + "96": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "processor_019", + "obj_state": 3, "position_x": 208.79067993164062, "position_y": 359.0682067871094, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 128.0 + "width": 139.0 }, "initargs": "\"it was foo:\"", "midi_filters": null, @@ -3789,23 +4938,34 @@ "properties": {}, "type": "print" }, - "98": { + "97": { "connections": [ [] ], "do_onload": true, "gui_params": { + "debug": false, "display_type": "processor", - "height": 25.0, + "export_h": null, + "export_offset_x": 0, + "export_offset_y": 0, + "export_w": null, + "export_x": null, + "export_y": null, + "height": 25, "is_export": false, "layername": "12. Pattern: Conditionals 2", "no_export": false, + "obj_name": "processor_020", + "obj_state": 3, "position_x": 245.79067993164062, "position_y": 389.0682067871094, + "position_z": 0, "scope": "__patch__", "show_label": true, + "style": {}, "update_required": false, - "width": 206.0 + "width": 222.0 }, "initargs": "\"it was something else:\"", "midi_filters": null, @@ -3815,23 +4975,32 @@ "properties": {}, "type": "print" }, - "99": { + "98": { "connections": [ [] ], "do_onload": false, "gui_params": { + "clickchange": false, + "debug": false, + "default": "", "display_type": "text", - "height": 26.0, + "export_offset_x": 0, + "export_offset_y": 0, + "height": 33.0, "is_export": false, "layername": "13. Pattern: Conditionals 3", "no_export": false, + "obj_name": "text_057", + "obj_state": 3, "position_x": 39.7034912109375, "position_y": 28.57501220703125, - "scope": "", + "position_z": 0, + "scope": "__patch__", + "style": {}, "update_required": true, "value": "Pattern: Conditionals 3", - "width": 160.0 + "width": 248.0 }, "initargs": null, "midi_filters": null, @@ -3841,143 +5010,179 @@ "properties": {}, "type": "text", "value": "Pattern: Conditionals 3" + }, + "99": { + "connections": [ + [] + ], + "do_onload": false, + "gui_params": { + "clickchange": false, + "debug": false, + "default": "", + "display_type": "text", + "export_offset_x": 0, + "export_offset_y": 0, + "height": 85.0, + "is_export": false, + "layername": "13. Pattern: Conditionals 3", + "no_export": false, + "obj_name": "text_058", + "obj_state": 3, + "position_x": 43.88772201538086, + "position_y": 81.19505310058594, + "position_z": 0, + "scope": "__patch__", + "style": {}, + "update_required": true, + "value": "One last important thing: in both [route] and [case], if the objects \nto test against are Python type objects, any object of the indicated type \nwill match. Tests are done in left-to-right order with the first successful match\naccepted. ", + "width": 563.0 + }, + "initargs": null, + "midi_filters": null, + "midi_mode": null, + "name": "text_058", + "osc_methods": [], + "properties": {}, + "type": "text", + "value": "One last important thing: in both [route] and [case], if the objects \nto test against are Python type objects, any object of the indicated type \nwill match. Tests are done in left-to-right order with the first successful match\naccepted. " } }, "scopes": { "__patch__": { - "button_013": 44, - "dial_001": 48, - "enum_001": 36, - "enum_002": 118, - "enum_003": 123, - "message_001": 30, - "message_002": 34, - "message_003": 56, - "message_004": 65, - "message_005": 66, - "message_006": 67, - "message_007": 68, - "message_008": 73, - "message_009": 76, - "message_010": 77, - "message_011": 80, - "message_012": 81, - "message_013": 82, - "message_014": 83, - "message_015": 91, - "message_016": 92, - "message_017": 93, - "message_018": 101, - "message_019": 102, - "message_020": 103, - "message_021": 110, - "message_022": 111, - "message_023": 114, - "message_024": 115, - "patch": 1, - "processor_001": 31, - "processor_002": 35, - "processor_003": 57, - "processor_004": 74, - "processor_005": 58, - "processor_006": 59, - "processor_007": 60, - "processor_008": 69, - "processor_009": 70, - "processor_010": 75, - "processor_011": 84, - "processor_012": 88, - "processor_013": 85, - "processor_014": 86, - "processor_015": 87, - "processor_016": 94, - "processor_017": 95, - "processor_018": 96, - "processor_019": 97, - "processor_020": 98, - "processor_021": 104, - "processor_022": 105, - "processor_023": 106, - "processor_024": 107, - "processor_025": 108, - "processor_026": 109, - "processor_027": 116, - "processor_028": 117, - "processor_029": 119, - "processor_030": 120, - "processor_031": 124, - "processor_032": 127, - "processor_033": 126, - "processor_034": 128, - "processor_035": 129, - "processor_036": 130, - "processor_037": 131, - "processor_038": 132, - "processor_039": 133, - "self": 1, - "slidemeter_001": 46, - "text_002": 2, - "text_003": 3, - "text_004": 14, - "text_005": 4, - "text_006": 50, - "text_007": 5, - "text_008": 52, - "text_009": 54, - "text_010": 6, - "text_011": 7, - "text_012": 55, - "text_013": 61, - "text_014": 8, - "text_015": 9, - "text_016": 62, - "text_017": 63, - "text_018": 10, - "text_019": 11, - "text_020": 12, - "text_021": 13, - "text_022": 15, - "text_023": 16, - "text_024": 17, - "text_025": 18, - "text_026": 19, - "text_027": 20, - "text_028": 21, - "text_029": 64, - "text_030": 71, - "text_031": 22, - "text_032": 23, - "text_033": 24, - "text_034": 25, - "text_035": 26, - "text_036": 27, - "text_037": 28, - "text_038": 29, - "text_039": 72, - "text_040": 78, - "text_041": 32, - "text_042": 51, - "text_043": 53, - "text_044": 33, - "text_045": 37, - "text_046": 38, - "text_047": 39, - "text_048": 40, - "text_049": 41, - "text_050": 43, - "text_051": 45, - "text_052": 47, - "text_053": 49, - "text_054": 79, - "text_055": 89, - "text_056": 90, - "text_057": 99, - "text_058": 100, - "text_059": 112, - "text_060": 113, - "text_061": 121, - "text_062": 122, - "toggle_001": 42 + "button_013": 43, + "dial_001": 47, + "enum_001": 35, + "enum_002": 117, + "enum_003": 122, + "message_001": 29, + "message_002": 33, + "message_003": 55, + "message_004": 64, + "message_005": 65, + "message_006": 66, + "message_007": 67, + "message_008": 72, + "message_009": 75, + "message_010": 76, + "message_011": 79, + "message_012": 80, + "message_013": 81, + "message_014": 82, + "message_015": 90, + "message_016": 91, + "message_017": 92, + "message_018": 100, + "message_019": 101, + "message_020": 102, + "message_021": 109, + "message_022": 110, + "message_023": 113, + "message_024": 114, + "patch": 0, + "processor_001": 30, + "processor_002": 34, + "processor_003": 56, + "processor_004": 73, + "processor_005": 57, + "processor_006": 58, + "processor_007": 59, + "processor_008": 68, + "processor_009": 69, + "processor_010": 74, + "processor_011": 83, + "processor_012": 87, + "processor_013": 84, + "processor_014": 85, + "processor_015": 86, + "processor_016": 93, + "processor_017": 94, + "processor_018": 95, + "processor_019": 96, + "processor_020": 97, + "processor_021": 103, + "processor_022": 104, + "processor_023": 105, + "processor_024": 106, + "processor_025": 107, + "processor_026": 108, + "processor_027": 115, + "processor_028": 116, + "processor_029": 118, + "processor_030": 119, + "processor_031": 123, + "processor_032": 125, + "processor_033": 124, + "processor_034": 126, + "processor_035": 127, + "processor_036": 128, + "processor_037": 129, + "processor_038": 130, + "processor_039": 131, + "self": 0, + "slidemeter_001": 45, + "text_002": 1, + "text_003": 2, + "text_004": 13, + "text_005": 3, + "text_006": 49, + "text_007": 4, + "text_008": 51, + "text_009": 53, + "text_010": 5, + "text_011": 6, + "text_012": 54, + "text_013": 60, + "text_014": 7, + "text_015": 8, + "text_016": 61, + "text_017": 62, + "text_018": 9, + "text_019": 10, + "text_020": 11, + "text_021": 12, + "text_022": 14, + "text_023": 15, + "text_024": 16, + "text_025": 17, + "text_026": 18, + "text_027": 19, + "text_028": 20, + "text_029": 63, + "text_030": 70, + "text_031": 21, + "text_032": 22, + "text_033": 23, + "text_034": 24, + "text_035": 25, + "text_036": 26, + "text_037": 27, + "text_038": 28, + "text_039": 71, + "text_040": 77, + "text_041": 31, + "text_042": 50, + "text_043": 52, + "text_044": 32, + "text_045": 36, + "text_046": 37, + "text_047": 38, + "text_048": 39, + "text_049": 40, + "text_050": 42, + "text_051": 44, + "text_052": 46, + "text_053": 48, + "text_054": 78, + "text_055": 88, + "text_056": 89, + "text_057": 98, + "text_058": 99, + "text_059": 111, + "text_060": 112, + "text_061": 120, + "text_062": 121, + "toggle_001": 41 } }, "type": "tutorial" diff --git a/mfp.desktop b/mfp.desktop new file mode 100644 index 0000000..5d900fe --- /dev/null +++ b/mfp.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=1.0 +Type=Application +Terminal=false +Exec=${PREFIX}/bin/mfp +Name=mfp +Icon=${PREFIX}/share/mfp/icons/hicolor/scalable/actions/mfp.svg diff --git a/mfp.svg b/mfp.svg new file mode 100644 index 0000000..c468fc9 --- /dev/null +++ b/mfp.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/mfp/bang.py b/mfp/bang.py index 3ee9cf7..81ca8ef 100644 --- a/mfp/bang.py +++ b/mfp/bang.py @@ -1,19 +1,22 @@ from .singleton import Singleton +from carp.serializer import Serializable -class BangType (Singleton): +class BangType (Serializable, Singleton): def __repr__(self): return "Bang" + def to_dict(self): + return {} + @classmethod def load(klass, objdict): return Bang -class UninitType (Singleton): +class UninitType (Serializable, Singleton): def __repr__(self): return "Uninit" - def __add__(self, other): return self diff --git a/mfp/buffer_info.py b/mfp/buffer_info.py index c6d77c3..50170bf 100644 --- a/mfp/buffer_info.py +++ b/mfp/buffer_info.py @@ -1,13 +1,26 @@ +""" +BufferInfo -- describe a sysv shared memory buffer +""" +from carp.serializer import Serializable -class BufferInfo(object): - def __init__(self, buf_id, size, channels, rate, offset=0): - self.buf_id = buf_id - self.size = size - self.channels = channels - self.rate = rate - self.offset = offset - def __repr__(self): - return "" % (self.buf_id, self.channels, self.size, self.rate) +class BufferInfo(Serializable): + def __init__(self, *, buf_id, size, channels, rate, offset=0): + self.buf_id = buf_id + self.size = int(size) + self.channels = int(channels) + self.rate = int(rate) + self.offset = int(offset) + super().__init__() + def to_dict(self): + return dict( + buf_id=self.buf_id, + size=self.size, + channels=self.channels, + rate=self.rate, + offset=self.offset + ) + def __repr__(self): + return f"" diff --git a/mfp/builtins/buffer.py b/mfp/builtins/buffer.py index 97cecce..bf4b8ec 100644 --- a/mfp/builtins/buffer.py +++ b/mfp/builtins/buffer.py @@ -81,8 +81,13 @@ def dsp_response(self, resp_id, resp_value): elif resp_id == self.RESP_OFFSET: self.buf_offset = resp_value elif resp_id == self.RESP_BUFRDY: - self.outlets[2] = BufferInfo(self.buf_id, self.size, self.channels, self.rate, - self.buf_offset) + self.outlets[2] = BufferInfo( + buf_id=self.buf_id, + size=self.size, + channels=self.channels, + rate=self.rate, + offset=self.buf_offset + ) async def trigger(self): incoming = self.inlets[0] @@ -125,8 +130,13 @@ def slice(self, start, end, channel=0): return None def bufinfo(self): - self.outlets[2] = BufferInfo(self.buf_id, self.size, self.channels, self.rate, - self.buf_offset) + self.outlets[2] = BufferInfo( + buf_id=self.buf_id, + size=self.size, + channels=self.channels, + rate=self.rate, + offset=self.buf_offset + ) def register(): diff --git a/mfp/builtins/plot.py b/mfp/builtins/plot.py index 983ac6b..b429852 100644 --- a/mfp/builtins/plot.py +++ b/mfp/builtins/plot.py @@ -38,19 +38,20 @@ async def trigger(self): if isinstance(self.inlets[0], BufferInfo): self.buffer = self.inlets[0] if self.gui_created: - MFPApp().gui_command.command(self.obj_id, "buffer", self.buffer) + await MFPApp().gui_command.command(self.obj_id, "buffer", self.buffer) + self.need_buffer_send = False else: self.need_buffer_send = True elif self.inlets[0] == 1: pass elif self.inlets[0] == 0: if self.gui_created: - self.grab() + await self.grab() + if self.buffer is None: - log.debug("scope: got input from buffer, but no bufferinfo.. requesting") self.outlets[0] = MethodCall("bufinfo") - if self.gui_created and self.need_buffer_send: + if self.gui_created and self.buffer and self.need_buffer_send: self.need_buffer_send = False MFPApp().gui_command.command(self.obj_id, "buffer", self.buffer) @@ -64,8 +65,8 @@ def set_retrig(self, value): def draw_complete(self): self.outlets[0] = self.retrig_value - def grab(self): - MFPApp().gui_command.command(self.obj_id, "grab", None) + async def grab(self): + await MFPApp().gui_command.command(self.obj_id, "grab", None) class Scatter (Processor): diff --git a/mfp/builtins/pulse.py b/mfp/builtins/pulse.py index e02976c..aa83923 100644 --- a/mfp/builtins/pulse.py +++ b/mfp/builtins/pulse.py @@ -36,9 +36,9 @@ class Pulse(Processor): def __init__(self, init_type, init_args, patch, scope, name): Processor.__init__(self, 4, 1, init_type, init_args, patch, scope, name) initargs, kwargs = self.parse_args(init_args) - freq = 0 - ampl = 1.0 - pw = 0.5 + self.init_freq = 0 + self.init_ampl = 1.0 + self.init_pw = 0.5 self.init_loval = -1.0 self.init_hival = 1.0 self.init_mode = 0 @@ -47,11 +47,11 @@ def __init__(self, init_type, init_args, patch, scope, name): self.init_loval = 0.0 if len(initargs) > 0: - freq = initargs[0] + self.init_freq = initargs[0] if len(initargs) > 1: - ampl = initargs[1] + self.init_ampl = initargs[1] if len(initargs) > 2: - pw = initargs[2] + self.init_pw = initargs[2] if len(initargs) > 3: if initargs[3] == 'ms': self.init_mode = 1 @@ -64,9 +64,9 @@ def __init__(self, init_type, init_args, patch, scope, name): async def setup(self): await self.dsp_init( "pulse~", - _sig_1=float(freq), - _sig_2=float(ampl), - _sig_3=float(pw), + _sig_1=float(self.init_freq), + _sig_2=float(self.init_ampl), + _sig_3=float(self.init_pw), hival=self.init_hival, loval=self.init_loval, pw_mode=self.init_mode diff --git a/mfp/builtins/pulsesel.py b/mfp/builtins/pulsesel.py index 026192a..4332dbb 100644 --- a/mfp/builtins/pulsesel.py +++ b/mfp/builtins/pulsesel.py @@ -1,4 +1,3 @@ - #! /usr/bin/env python ''' pulsesel.py: Select some pulses from a pulse train @@ -13,26 +12,27 @@ class PulseSel(Processor): doc_tooltip_obj = "Pulse train divider/selector" - doc_tooltip_inlet = ["Signal input/reset", - "Period", - "Selection bitmask", - "Trigger threshold (default: 0.25)", - ] + doc_tooltip_inlet = [ + "Signal input/reset", + "Period", + "Selection bitmask", + "Trigger threshold (default: 0.25)", + ] doc_tooltip_outlet = ["Signal output"] def __init__(self, init_type, init_args, patch, scope, name): Processor.__init__(self, 4, 1, init_type, init_args, patch, scope, name) initargs, kwargs = self.parse_args(init_args) - period = 2 - bitmask = 1 - thresh = 0.25 + self.init_period = 2 + self.init_bitmask = 1 + self.init_thresh = 0.25 if len(initargs) > 0: - period = initargs[0] + self.init_period = initargs[0] if len(initargs) > 1: - bitmask = initargs[1] + self.init_bitmask = initargs[1] if len(initargs) > 2: - thresh = initargs[2] + self.init_thresh = initargs[2] self.dsp_inlets = [0] self.hot_inlets = [0, 1, 2, 3] @@ -41,15 +41,15 @@ def __init__(self, init_type, init_args, patch, scope, name): async def setup(self): await self.dsp_init( "pulsesel~", - bitmask=bitmask, period=period, threshold=thresh + bitmask=self.init_bitmask, period=self.init_period, threshold=self.init_thresh ) async def trigger(self): if self.inlets[0] is Bang: await self.dsp_setparam("phase", float(0)) elif self.inlets[0] is not Uninit: - await self.dsp_setparam("phase", phase) - + await self.dsp_setparam("phase", self.inlets[0]) + if self.inlets[1] is not Uninit: await self.dsp_setparam("period", self.inlets[1]) self.inlets[1] = Uninit @@ -62,5 +62,6 @@ async def trigger(self): await self.dsp_setparam("threshold", self.inlets[3]) self.inlets[3] = Uninit + def register(): MFPApp().register("pulsesel~", PulseSel) diff --git a/mfp/builtins/stepseq.py b/mfp/builtins/stepseq.py index 74b429b..08aa4b6 100644 --- a/mfp/builtins/stepseq.py +++ b/mfp/builtins/stepseq.py @@ -49,7 +49,7 @@ def convert_steps(self, steps): unpacked = [] for s in steps: if isinstance(s, (float, int)): - unpacked.extend([float(s), True, float(0.0)]) + unpacked.extend([float(s), float(1.0), float(0.0)]) elif len(s) > 2: unpacked.extend([float(s[0]), float(s[1]), float(s[2])]) elif len(s) == 2: diff --git a/mfp/builtins/var.py b/mfp/builtins/var.py index ea1b86c..2bd8551 100644 --- a/mfp/builtins/var.py +++ b/mfp/builtins/var.py @@ -20,11 +20,11 @@ class Var (Processor): ''' doc_tooltip_obj = "Store a variable message (any type)" - doc_tooltip_inlet = ["Save input and emit from outlet, or only emit if input is Bang", + doc_tooltip_inlet = ["Save input and emit from outlet, or only emit if input is Bang", "Save input but do not emit (default: initarg 0)" ] doc_tooltip_outlet = ["Value output"] - do_onload = False + do_onload = False def __init__(self, init_type, init_args, patch, scope, name): self.gui_type = init_type @@ -46,14 +46,14 @@ async def onload(self, phase): async def trigger(self): ''' [var] trigger, basic form: - - on inlet 1, save value but do not output. - Possibly update GUI display. - - Bang on inlet 0: output stored value - - anything else on inlet 0: save and output value - Possibly update GUI display + - on inlet 1, save value but do not output. + Possibly update GUI display. + - Bang on inlet 0: output stored value + - anything else on inlet 0: save and output value + Possibly update GUI display As [text]: - - ensure that value is a string and save it in the gui_params + - ensure that value is a string and save it in the gui_params ''' do_update = False @@ -66,24 +66,20 @@ async def trigger(self): if self.inlets[0] is not Uninit: # Bang just causes output - if (self.inlets[0] is not Bang): + if self.inlets[0] is not Bang: self.value = self.inlets[0] if self.init_type == "text": self.value = str(self.value) do_update = True self.outlets[0] = self.value self.inlets[0] = Uninit - if (do_update and self.gui_params.get("update_required") - and ('value' not in self.gui_params or self.gui_params['value'] != self.value)): + if ( + do_update and self.gui_params.get("update_required") + and ('value' not in self.gui_params or self.gui_params['value'] != self.value) + ): self.conf(value=self.value) return True - def save(self): - base_dict = Processor.save(self) - if self.init_type != "message": - base_dict["value"] = self.value - return base_dict - def load(self, params): Processor.load(self, params) if params.get("value"): @@ -101,18 +97,21 @@ def tooltip_extra(self): vs = str(self.value) if len(vs) > 30: dots = '...' - return "Value: %s%s" % (vs[:30], dots) + return "Value: %s%s" % (vs[:30], dots) -class Message (Var): + +class Message (Var): doc_tooltip_obj = "Store literal Python data as a message to emit when clicked/triggered" - doc_tooltip_inlet = ["Emit message on any input", - "Load new message but do not emit" ] + doc_tooltip_inlet = [ + "Emit message on any input", + "Load new message but do not emit" + ] def __init__(self, init_type, init_args, patch, scope, name): Var.__init__(self, init_type, init_args, patch, scope, name) self.hot_inlets = (0, 1) - async def trigger(self): + async def trigger(self): do_update = False if self.inlets[1] is not Uninit: self.value = self.inlets[1] @@ -127,22 +126,31 @@ async def trigger(self): self.gui_params['value'] = self.value self.conf(value=self.value) - def save(self): - return Processor.save(self) class Text (Var): doc_tooltip_obj = "Comment using SGML-type markup for style" + def save(self): + base_dict = super().save() + base_dict["value"] = self.value + return base_dict + + class Enum (Var): doc_tooltip_obj = "Enter and update a numeric message" + def save(self): + base_dict = super().save() + base_dict["value"] = self.value + return base_dict + def tooltip_extra(self): minv = self.gui_params.get("min_value") - maxv = self.gui_params.get("max_value") + maxv = self.gui_params.get("max_value") digits = self.gui_params.get("digits", 1) - ffmt = "%%.%df" % digits + ffmt = "%%.%df" % digits - vv = '' + vv = '' if minv is not None or maxv is not None: vv = "val" @@ -154,20 +162,26 @@ def tooltip_extra(self): if vv != '': vv = "Range: (%s)" % vv - else: - vv = None - return [ vv, Var.tooltip_extra(self) ] + else: + vv = None + return [vv, Var.tooltip_extra(self)] + class SlideMeter (Var): doc_tooltip_obj = "Display/control a number with a slider" - do_onload = True + do_onload = True + + def save(self): + base_dict = super().save() + base_dict["value"] = self.value + return base_dict def tooltip_extra(self): minv = self.gui_params.get("min_value") - maxv = self.gui_params.get("max_value") + maxv = self.gui_params.get("max_value") ffmt = "%.1f" - vv = '' + vv = '' if minv is not None or maxv is not None: vv = "val" @@ -180,7 +194,8 @@ def tooltip_extra(self): if vv != '': vv = " (%s)" % vv - return [ 'Range: ' + vv, Var.tooltip_extra(self) ] + return ['Range: ' + vv, Var.tooltip_extra(self)] + def register(): MFPApp().register("var", Var) diff --git a/mfp/builtins/vcq12.py b/mfp/builtins/vcq12.py index 66d9e74..6ef8fc1 100644 --- a/mfp/builtins/vcq12.py +++ b/mfp/builtins/vcq12.py @@ -50,7 +50,7 @@ def __init__(self, init_type, init_args, patch, scope, name): self.init_mapvals = [val for pair in self.map for val in pair] async def setup(self): - await self.dsp_init("vcq12~", map=self.mapvals) + await self.dsp_init("vcq12~", map=self.init_mapvals) async def trigger(self): if self.inlets[1] is not Uninit: @@ -58,6 +58,6 @@ async def trigger(self): self.map = self.maps.get(self.mapname, self.maps['semitone']) await self.dsp_setparam("map", [val for pair in self.map for val in pair]) + def register(): MFPApp().register("vcq12~", VCQ12) - diff --git a/mfp/gui/app_window.py b/mfp/gui/app_window.py index e6ea574..8b87a48 100644 --- a/mfp/gui/app_window.py +++ b/mfp/gui/app_window.py @@ -133,13 +133,6 @@ def active_layer(self): return self.selected_layer - # FIXME clutter - def ready(self): - if self.window and self.window.get_realized(): - return True - else: - return False - def edit_major_mode(self): for o in self.selected: o.end_control() @@ -168,7 +161,6 @@ def register(self, element): if element.obj_id is not None: element.send_params() - def unregister(self, element): if element in self.selected: MFPGUI().async_task(self.unselect(element)) @@ -239,8 +231,8 @@ def console_show_prompt(self, msg): self.console_manager.show_prompt(msg) self.console_activate() - def get_prompted_input(self, prompt, callback, default=''): - self.hud_prompt_mgr.get_input(prompt, callback, default) + async def get_prompted_input(self, prompt, callback, default=''): + await self.hud_prompt_mgr.get_input(prompt, callback, default) # additional methods in @extends wrappers from . import app_window_layer # noqa diff --git a/mfp/gui/app_window_select.py b/mfp/gui/app_window_select.py index 949ca79..527facf 100644 --- a/mfp/gui/app_window_select.py +++ b/mfp/gui/app_window_select.py @@ -177,11 +177,13 @@ async def select_mru(self): @extends(AppWindow) -def move_selected(self, dx, dy): +async def move_selected(self, dx, dy): for obj in self.selected: if obj.editable and obj.display_type != 'connection': - obj.move(max(0, obj.position_x + dx * self.zoom), - max(0, obj.position_y + dy * self.zoom)) + await obj.move( + max(0, obj.position_x + dx * self.zoom), + max(0, obj.position_y + dy * self.zoom) + ) if obj.obj_id is not None: obj.send_params() if self.selected: diff --git a/mfp/gui/backend_interfaces.py b/mfp/gui/backend_interfaces.py index 2b54ca4..a576bc3 100644 --- a/mfp/gui/backend_interfaces.py +++ b/mfp/gui/backend_interfaces.py @@ -56,6 +56,11 @@ def render(self): def grab_focus(self): pass + @abstractmethod + @delegatemethod + def ready(self): + pass + ##################### # coordinate transforms and zoom diff --git a/mfp/gui/base_element.py b/mfp/gui/base_element.py index 1b1ba5a..81111e7 100644 --- a/mfp/gui/base_element.py +++ b/mfp/gui/base_element.py @@ -6,7 +6,7 @@ Copyright (c) 2011 Bill Gribble ''' -from flopsy import Store +from flopsy import Store, mutates from mfp.gui_main import MFPGUI from mfp import log from .colordb import ColorDB @@ -17,11 +17,11 @@ class BaseElement (Store): Parent class of elements represented in the patch window ''' store_attrs = [ - 'position_x', 'position_y', 'width', 'height', + 'position_x', 'position_y', 'position_z', 'width', 'height', 'update_required', 'display_type', 'name', 'layername', 'no_export', 'is_export', 'num_inlets', 'num_outlets', 'dsp_inlets', 'dsp_outlets', 'scope', 'style', 'export_offset_x', - 'export_offset_y', 'debug' + 'export_offset_y', 'debug', 'obj_name', 'obj_state' ] style_defaults = { @@ -73,6 +73,7 @@ def __init__(self, window, x, y): # could be the same as self.container but is definitely a layer self.layer = None + self.layername = None self.tags = {} @@ -84,8 +85,8 @@ def __init__(self, window, x, y): self.export_offset_y = 0 self.width = None self.height = None - self.drag_x = None - self.drag_y = None + self.drag_start_x = None + self.drag_start_y = None self.selected = False self.editable = True self.debug = False @@ -115,10 +116,6 @@ def corners(self): (self.position_x + self.width, self.position_y + self.height), (self.position_x, self.position_y + self.height)] - @property - def layername(self): - return self.layer.name if self.layer else None - @property def name(self): return self.obj_name @@ -126,16 +123,35 @@ def name(self): def get_size(self): return (self.width, self.height) - def set_size(self, width, height): - if ( - self.width and self.height - and abs(width - self.width) < BaseElement.TINY_DELTA - and abs(height - self.height) < BaseElement.TINY_DELTA - ): + async def set_size(self, width, height, update_state=True, **kwargs): + prev_width = kwargs.get('width', self.width) + prev_height = kwargs.get('height', self.height) + changed_w = not self.width or abs(width - self.width) > BaseElement.TINY_DELTA + changed_h = not self.height or abs(height - self.height) > BaseElement.TINY_DELTA + + if self.width and self.height and not changed_w and not changed_h: return - self.width = width - self.height = height + if update_state: + if changed_w: + await self.dispatch( + self.action( + self.SET_WIDTH, + value=width, + ), + previous=dict(width=prev_width) + ) + if changed_h: + await self.dispatch( + self.action( + self.SET_HEIGHT, + value=height, + ), + previous=dict(height=prev_height) + ) + else: + self.width = width + self.height = height self.draw_ports() self.send_params() @@ -149,9 +165,6 @@ def get_style(self, propname): def get_position(self): return (self.position_x, self.position_y) - def set_position(self, x, y): - self.move(x, y) - def get_fontspec(self): return '{} {}px'.format(self.get_style('font-face'), self.get_style('font-size')) @@ -185,7 +198,7 @@ def combine_styles(self): styles.update(styleset) return styles - def update(self): + async def update(self): pass def event_source(self): @@ -200,13 +213,48 @@ def unselect(self): self.selected = False self.draw_ports() - def drag_start(self, x, y): - self.drag_x = x - self.position_x - self.drag_y = y - self.position_y + def drag_start(self): + self.drag_start_x = self.position_x + self.drag_start_y = self.position_y + + async def drag_end(self): + await self.move( + self.position_x, + self.position_y, + update_state=True, + previous_x=self.drag_start_x, + previous_y=self.drag_start_y + ) - def drag(self, dx, dy): - self.move(self.position_x + dx, self.position_y + dy) + async def drag(self, dx, dy): + await self.move(self.position_x + dx, self.position_y + dy, update_state=False) + + async def move(self, x, y, update_state=True, **kwargs): + previous_x = kwargs.get('previous_x', self.position_x) + previous_y = kwargs.get('previous_y', self.position_y) + + if update_state: + if previous_x is None or abs(x - previous_x) > self.TINY_DELTA: + await self.dispatch( + self.action( + self.SET_POSITION_X, + value=x, + ), + previous=dict(position_x=previous_x) + ) + if previous_y is None or abs(y - previous_y) > self.TINY_DELTA: + await self.dispatch( + self.action( + self.SET_POSITION_Y, + value=y, + ), + previous=dict(position_y=previous_y) + ) + else: + self.position_x = x + self.position_y = y + @mutates('obj_state') async def delete(self): # FIXME this is because self.app_window is the backend, not the app window MFPGUI().appwin.unregister(self) @@ -242,6 +290,11 @@ async def create(self, obj_type, init_args): await MFPGUI().mfp.delete(self.obj_id) self.obj_id = None + # need to emit this signal before creating so that if + # create() makes sub-objects with visible elements they + # get put in the correct place in the object tree + await MFPGUI().appwin.signal_emit("created", self) + objinfo = await MFPGUI().mfp.create(obj_type, init_args, patchname, scopename, name) if self.layer is not None and objinfo: objinfo["layername"] = self.layer.name @@ -252,6 +305,7 @@ async def create(self, obj_type, init_args): self.connections_in = connections_in return None + # FIXME flopsy self.obj_id = objinfo.get('obj_id') self.obj_name = objinfo.get('name') self.obj_args = objinfo.get('initargs') @@ -264,13 +318,15 @@ async def create(self, obj_type, init_args): if self.obj_id is not None: MFPGUI().remember(self) - self.configure(objinfo) + await self.configure(objinfo) # rebuild connections if necessary for c in connections_in: if c.obj_2 is self and c.port_2 >= self.num_inlets: c.obj_2 = None await c.delete() + elif c.obj_1 is None or c.obj_2 is None: + await c.delete() else: self.connections_in.append(c) if not c.dashed: @@ -282,6 +338,8 @@ async def create(self, obj_type, init_args): if c.obj_1 is self and c.port_1 >= self.num_outlets: c.obj_1 = None await c.delete() + elif c.obj_1 is None or c.obj_2 is None: + await c.delete() else: self.connections_out.append(c) if not c.dashed: @@ -289,10 +347,9 @@ async def create(self, obj_type, init_args): c.obj_1.obj_id, c.port_1, c.obj_2.obj_id, c.port_2 ) self.draw_ports() - self.send_params() + await MFPGUI().mfp.set_gui_created(self.obj_id, True) - await MFPGUI().appwin.signal_emit("created", self) self.app_window.refresh(self) @@ -367,7 +424,12 @@ def port_position(self, port_dir, port_num): return (self.get_style('porthole_border') + spc * port_num, h - self.get_style('porthole_height')) - def configure(self, params): + @mutates( + 'num_inlets', 'num_outlets', 'dsp_inlets', 'dsp_outlets', + 'obj_name', 'no_export', 'is_export', 'export_offset_x', + 'export_offset_y', 'debug', 'layername' + ) + async def configure(self, params): self.num_inlets = params.get("num_inlets", 0) self.num_outlets = params.get("num_outlets", 0) self.dsp_inlets = params.get("dsp_inlets", []) @@ -412,17 +474,18 @@ def configure(self, params): xpos = params['position_x'] ypos = params['position_y'] - self.move(xpos, ypos) + await self.move(xpos, ypos) if "z_index" in params: self.move_z(params.get("z_index")) if (w != w_orig) or (h != h_orig): - self.set_size(w, h) + await self.set_size(w, h) self.draw_ports() self.app_window.refresh(self) + @mutates('layername') def move_to_layer(self, layer): layer_child = False if layer and layer == self.layer: @@ -457,6 +520,7 @@ async def begin_edit(self): if not self.edit_mode: self.edit_mode = await self.make_edit_mode() + await self.edit_mode.setup() if self.edit_mode: self.app_window.input_mgr.enable_minor_mode(self.edit_mode) @@ -503,3 +567,6 @@ async def show_tip(self, xpos, ypos, details): tiptxt = await MFPGUI().mfp.get_tooltip(self.obj_id, None, None, details) self.app_window.hud_banner(tiptxt) return True + + def command(self, action, args): + pass diff --git a/mfp/gui/button_element.py b/mfp/gui/button_element.py index e308cf4..da43e86 100644 --- a/mfp/gui/button_element.py +++ b/mfp/gui/button_element.py @@ -73,7 +73,7 @@ def __init__(self, window, x, y): def get_factory(cls): return ButtonElementImpl.get_backend(MFPGUI().appwin.backend_name) - def center_label(self): + async def center_label(self): label_halfwidth = self.label.get_property('width')/2.0 label_halfheight = self.label.get_property('height')/2.0 @@ -81,17 +81,17 @@ def center_label(self): nwidth = max(self.width, 2*label_halfwidth + 10) nheight = max(self.height, 2*label_halfheight + 10) if nwidth != self.width or nheight != self.height: - self.set_size(nwidth, nheight) + await self.set_size(nwidth, nheight) if self.width and self.height: self.label.set_position(self.width/2.0-label_halfwidth, self.height/2.0-label_halfheight-2) @catchall - def label_changed_cb(self, *args): - self.center_label() + async def label_changed_cb(self, *args): + await self.center_label() - def label_edit_start(self): + async def label_edit_start(self): return self.label_text async def label_edit_finish(self, widget, new_text, aborted=False): @@ -105,7 +105,7 @@ async def label_edit_finish(self, widget, new_text, aborted=False): self.redraw() - def configure(self, params): + async def configure(self, params): set_text = False if "value" in params: @@ -122,9 +122,9 @@ def configure(self, params): self.label.set_markup("%s" % (self.label_text or '')) else: self.label.set_markup(self.label_text or '') - self.center_label() + await self.center_label() - super().configure(params) + await super().configure(params) self.redraw() def select(self): @@ -165,7 +165,7 @@ def __init__(self, window, x, y): def get_factory(cls): return BangButtonElementImpl.get_backend(MFPGUI().appwin.backend_name) - def clicked(self): + async def clicked(self): if self.obj_id is not None: if self.message is Bang: MFPGUI().async_task(MFPGUI().mfp.send_bang(self.obj_id, 0)) @@ -182,11 +182,11 @@ def unclicked(self): return False - def configure(self, params): + async def configure(self, params): if "message" in params: self.message = params.get("message") - super().configure(params) + await super().configure(params) class ToggleButtonElement (ButtonElement): @@ -203,7 +203,7 @@ def __init__(self, window, x, y): def get_factory(cls): return ToggleButtonElementImpl.get_backend(MFPGUI().appwin.backend_name) - def clicked(self): + async def clicked(self): message = None if self.indicator: message = self.off_message @@ -217,12 +217,12 @@ def clicked(self): self.redraw() return False - def configure(self, params): + async def configure(self, params): if "on_message" in params: self.on_message = params.get("on_message") if "off_message" in params: self.off_message = params.get("off_message") - ButtonElement.configure(self, params) + await super().configure(params) async def create(self, init_type, init_args): await super().create(init_type, init_args) diff --git a/mfp/gui/clutter/app_window.py b/mfp/gui/clutter/app_window.py index ff1f057..9371e1e 100644 --- a/mfp/gui/clutter/app_window.py +++ b/mfp/gui/clutter/app_window.py @@ -62,6 +62,12 @@ def initialize(self): log.debug_traceback() sys.stdout.flush() + def ready(self): + if self.window and self.window.get_realized(): + return True + else: + return False + def _init_window(self): from gi.repository import Clutter, Gtk, GtkClutter # load Glade ui @@ -83,6 +89,10 @@ def _init_window(self): self.hud_prompt = None self.hud_prompt_input = None self.hud_mode_txt = None + + self.previous_console_position = 0 + self.next_tree_position = 1 + ############################ ############################ @@ -127,7 +137,7 @@ def _init_window(self): # set app icon icon_theme = Gtk.IconTheme.get_default() - icon_name = "mfp-icon" + icon_name = "mfp" icon_path = sys.exec_prefix + '/share/mfp/icons/' icon_theme.add_resource_path(icon_path) icon_theme.append_search_path(icon_path) @@ -136,9 +146,11 @@ def _init_window(self): icon_theme.load_icon(icon_name, s, 0) for s in sizes ] - log.debug(f"loaded icons: {pixbufs}") self.window.set_icon_list(pixbufs) + self.wrapper.signal_listen("toggle-console", self._toggle_console) + self.wrapper.signal_listen("toggle-info-panel", self._toggle_info_panel) + # show top-level window self.window.show_all() @@ -307,10 +319,10 @@ def leader_iters(): start_it, end_it = leader_iters() buf.apply_tag(monotag, start_it, end_it) - if (level == 1): + if level == 1: start_it, end_it = leader_iters() buf.apply_tag(warntag, start_it, end_it) - elif (level == 2): + elif level == 2: start_it, end_it = leader_iters() buf.apply_tag(errtag, start_it, end_it) @@ -584,7 +596,9 @@ def register(self, element): def unregister(self, element): if element.container: if isinstance(element.container, BaseElement): - element.container.remove(element) + parent = element.group.get_parent() + if parent: + parent.remove_child(element.group) element.container = None self.object_view.remove(element) @@ -632,3 +646,31 @@ def layer_select(self, layer): def layer_update(self, layer, patch): self.layer_view.update(layer, patch) + + async def _toggle_console(self, *args): + alloc = self.content_console_pane.get_allocation() + oldpos = self.content_console_pane.get_position() + + console_visible = oldpos < (alloc.height - 2) + if console_visible: + next_pos = alloc.height + self.previous_console_position = oldpos + else: + next_pos = self.previous_console_position + + self.content_console_pane.set_position(next_pos) + + async def _toggle_info_panel(self, *args): + def refresh(): + oldpos = self.content_console_pane.get_position() + self.content_console_pane.set_position(oldpos - 1) + return False + + from mfp.gui.clutter.utils import clutter_do_later + oldpos = self.tree_canvas_pane.get_position() + + self.tree_canvas_pane.set_position(self.next_tree_position) + self.next_tree_position = oldpos + + # KLUDGE! + clutter_do_later(100, refresh) diff --git a/mfp/gui/clutter/base_element.py b/mfp/gui/clutter/base_element.py index 09a8684..d730e68 100644 --- a/mfp/gui/clutter/base_element.py +++ b/mfp/gui/clutter/base_element.py @@ -6,6 +6,7 @@ import math from gi.repository import Clutter +from flopsy import mutates from mfp.gui_main import MFPGUI from mfp.gui.base_element import BaseElement @@ -89,7 +90,7 @@ def draw_badge_cb(self, tex, ctx): def update_badge(self): if self.group is None: - return + return badgesize = self.get_style('badge_size') if self.badge is None: @@ -188,12 +189,7 @@ def confport(pid, px, py): del self.port_elements[pid] self.group.remove_actor(port) - # redraw connections - for c in self.connections_out: - c.draw() - - for c in self.connections_in: - c.draw() + MFPGUI().async_task(self.redraw_connections()) def hide_ports(self): def hideport(pid): @@ -209,9 +205,16 @@ def hideport(pid): pid = (BaseElement.PORT_OUT, i) hideport(pid) - def move(self, x, y): - self.position_x = x - self.position_y = y + async def redraw_connections(self): + # redraw connections + for c in self.connections_out: + await c.draw() + + for c in self.connections_in: + await c.draw() + + async def move(self, x, y, **kwargs): + await super().move(x, y, **kwargs) if not self.group: return @@ -219,16 +222,17 @@ def move(self, x, y): self.group.set_position(x, y) for c in self.connections_out: - c.draw() + await c.draw(update_state=kwargs.get("update_state", True)) for c in self.connections_in: - c.draw() + await c.draw(update_state=kwargs.get("update_state", True)) + @mutates('position_z') def move_z(self, z): self.position_z = z self.group.set_z_position(z) - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height, **kwargs): + await super().set_size(width, height, **kwargs) Clutter.Group.set_size(self.group, width, height) self.update_badge() diff --git a/mfp/gui/clutter/button_element.py b/mfp/gui/clutter/button_element.py index 52f478a..cf122ad 100644 --- a/mfp/gui/clutter/button_element.py +++ b/mfp/gui/clutter/button_element.py @@ -59,14 +59,16 @@ def __init__(self, window, x, y): # create elements self.texture = Clutter.Canvas.new() - self.texture.set_size(20, 20) self.texture.connect("draw", self.draw_cb) self.group.set_content(self.texture) self.group.set_reactive(True) - self.set_size(20, 20) - self.move(x, y) + self.width = 20 + self.height = 20 + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) + self.group.set_position(x, y) def redraw(self): self.texture.invalidate() @@ -75,8 +77,8 @@ def redraw(self): else: self.label.set_color(self.get_color('text-color')) - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) self.redraw() diff --git a/mfp/gui/clutter/colordb.py b/mfp/gui/clutter/colordb.py index 8f24ef3..d102072 100644 --- a/mfp/gui/clutter/colordb.py +++ b/mfp/gui/clutter/colordb.py @@ -27,7 +27,12 @@ def normalize(self, color): from mfp.gui.colordb import RGBAColor if color is not None: - rv = RGBAColor(color.red / 255.0, color.green / 255.0, color.blue/255.0, color.alpha/255.0) + rv = RGBAColor( + red=(color.red / 255.0), + green=(color.green / 255.0), + blue=(color.blue/255.0), + alpha=color.alpha/255.0 + ) else: - rv = RGBAColor(0, 0, 0, 1) + rv = RGBAColor(red=0, green=0, blue=0, alpha=1) return rv diff --git a/mfp/gui/clutter/connection_element.py b/mfp/gui/clutter/connection_element.py index 0c93855..2ab931e 100644 --- a/mfp/gui/clutter/connection_element.py +++ b/mfp/gui/clutter/connection_element.py @@ -33,11 +33,17 @@ def __init__(self, window, obj_1, port_1, obj_2, port_2, dashed=False): elif self.obj_2.layer is not None: self.move_to_layer(self.obj_2.layer) - self.set_size(15, 15) + self.width = 15 + self.height = 15 + self.texture.set_size(self.width, self.height) px, py = self.obj_1.get_position() - self.move(px, py) - self.draw() + self.position_x = px + self.position_y = py + self.texture.invalidate() + + async def update(self): + await self.draw() async def delete(self): if self.texture: @@ -46,35 +52,61 @@ async def delete(self): await super().delete() + def select(self): + super().select() + self.redraw() + + def unselect(self): + super().unselect() + self.redraw() + def redraw(self): super().redraw() - self.draw() + if self.texture: + self.texture.invalidate() - def draw(self): + async def draw(self, update_state=True, **kwargs): if self.obj_1 is None or self.obj_2 is None: return + prev_rotation = kwargs.get("rotation", self.rotation) p1 = self.obj_1.port_center(BaseElement.PORT_OUT, self.port_1) p2 = self.obj_2.port_center(BaseElement.PORT_IN, self.port_2) if self.dsp_connect is True: - self.width = 2.5 * self.LINE_WIDTH + width = 2.5 * self.LINE_WIDTH else: - self.width = 1.5 * self.LINE_WIDTH - self.height = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5 + width = 1.5 * self.LINE_WIDTH + height = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5 theta = math.atan2(p1[0] - p2[0], p2[1] - p1[1]) - self.rotation = theta * 180.0 / math.pi - self.position_x = p1[0] - math.cos(theta) * self.width / 2.0 - self.position_y = p1[1] - math.sin(theta) * self.width / 2.0 + rotation = theta * 180.0 / math.pi + position_x = p1[0] - math.cos(theta) * width / 2.0 + position_y = p1[1] - math.sin(theta) * width / 2.0 + + await self.move(position_x, position_y, update_state=update_state, **kwargs) + + if update_state and abs(prev_rotation-rotation) > BaseElement.TINY_DELTA: + await self.dispatch( + self.action( + self.SET_ROTATION, + value=rotation, + ), + previous=dict(rotation=prev_rotation) + ) + else: + self.rotation = rotation - self.set_position(self.position_x, self.position_y) + self.group.set_position(self.position_x, self.position_y) self.group.set_rotation(Clutter.RotateAxis.Z_AXIS, self.rotation, 0, 0, 0) - self.set_size(math.ceil(self.width), math.ceil(self.height)) + await self.set_size( + math.ceil(width), math.ceil(height), + update_state=update_state, + **kwargs + ) if self.texture: self.texture.invalidate() - def draw_cb(self, texture, ctx, width, height): # clear the drawing area ctx.save() @@ -109,16 +141,14 @@ def draw_cb(self, texture, ctx, width, height): def draw_ports(self): pass - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height, **kwargs): + await super().set_size(width, height, **kwargs) if self.texture: self.texture.set_size(width, height) self.texture.invalidate() - def move(self, x, y): - self.position_x = x - self.position_y = y - + async def move(self, x, y, **kwargs): + await super().move(x, y, **kwargs) self.group.set_position(x, y) def corners(self): diff --git a/mfp/gui/clutter/enum_element.py b/mfp/gui/clutter/enum_element.py index 5809c5c..85d47d6 100644 --- a/mfp/gui/clutter/enum_element.py +++ b/mfp/gui/clutter/enum_element.py @@ -27,8 +27,11 @@ def __init__(self, window, x, y): self.group.set_content(self.texture) self.group.set_reactive(True) - self.move(x, y) - self.set_size(35, 25) + self.group.set_position(x, y) + self.width = 35 + self.height = 25 + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) def redraw(self): super().redraw() @@ -69,8 +72,8 @@ def draw_cb(self, texture, ct, width, height): ct.set_source_rgba(color.red, color.green, color.blue, 1.0) ct.stroke() - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) self.texture.invalidate() diff --git a/mfp/gui/clutter/input_manager.py b/mfp/gui/clutter/input_manager.py index 58bc08c..bc36bb9 100644 --- a/mfp/gui/clutter/input_manager.py +++ b/mfp/gui/clutter/input_manager.py @@ -124,7 +124,6 @@ def handle_event(self, *args): ): self.input_manager.keyseq.mod_keys = set() self.input_manager.window.grab_focus() - if ( src and src != self.input_manager.window diff --git a/mfp/gui/clutter/layer.py b/mfp/gui/clutter/layer.py index 3ba5036..4b71083 100644 --- a/mfp/gui/clutter/layer.py +++ b/mfp/gui/clutter/layer.py @@ -4,6 +4,7 @@ from mfp import log + class ClutterLayerBackend(LayerBackend): backend_name = "clutter" @@ -29,20 +30,24 @@ def remove(self, obj): else: child = obj - self.group.remove_child(child) + parent = child.get_parent() + if parent: + parent.remove_child(child) - def add(self, obj): + def add(self, obj, container=None): if isinstance(obj, BaseElement): group = obj.group else: group = obj.backend.group + dest_group = (container and container.group) or self.group + parent = group.get_parent() child = group - if parent != self.group: + if parent != dest_group: if parent: parent.remove_child(child) - self.group.add_child(child) + dest_group.add_child(child) def delete(self): del self.group diff --git a/mfp/gui/clutter/message_element.py b/mfp/gui/clutter/message_element.py index 1361cd9..c614cae 100644 --- a/mfp/gui/clutter/message_element.py +++ b/mfp/gui/clutter/message_element.py @@ -31,9 +31,13 @@ def __init__(self, window, x, y): self.group.set_content(self.texture) self.group.set_reactive(True) - # resize widget whne text gets longer + # resize widget when text gets longer self.handler_id = self.label.signal_listen('text-changed', self.text_changed_cb) - self.set_size(35, 25) + self.width = 35 + self.height = 25 + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) + self.group.set_position(x, y) self.redraw() async def delete(self): @@ -53,13 +57,12 @@ def redraw(self): super().redraw() self.texture.invalidate() - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) - self.update() + await self.update() - @catchall - def text_changed_cb(self, *args): + async def text_changed_cb(self, *args): if self.group is None: return lwidth = self.label.get_property('width') @@ -72,10 +75,9 @@ def text_changed_cb(self, *args): new_w = max(35, lwidth + 20) if new_w is not None: - self.set_size(new_w, self.texture.get_property('height')) - self.update() + await self.set_size(new_w, self.texture.get_property('height')) + await self.update() - @catchall def draw_cb(self, texture, ct, width, height): if self.clickstate: lw = 5.0 diff --git a/mfp/gui/clutter/plot_element.py b/mfp/gui/clutter/plot_element.py index 9f2d2ac..e007d10 100644 --- a/mfp/gui/clutter/plot_element.py +++ b/mfp/gui/clutter/plot_element.py @@ -27,7 +27,6 @@ class ClutterPlotElementImpl(PlotElement, PlotElementImpl, ClutterBaseElementBac def __init__(self, window, x, y): super().__init__(window, x, y) - # display elements self.rect = None self.xyplot = None @@ -36,9 +35,13 @@ def __init__(self, window, x, y): width = self.INIT_WIDTH + self.WIDTH_PAD height = self.INIT_HEIGHT + self.LABEL_SPACE + self.HEIGHT_PAD self.create_display(width, height) - self.set_size(width, height) - self.move(x, y) - self.update() + self.width = width + self.height = height + self.rect.set_size(width, height) + if self.xyplot: + self.xyplot.set_size(width-self.WIDTH_PAD, height-self.LABEL_SPACE-self.WIDTH_PAD) + self.group.set_position(x, y) + self.draw_ports() @property def plot_style(self): @@ -54,8 +57,8 @@ def plot_type(self): return "scope" return "none" - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.rect.set_size(width, height) if self.xyplot: self.xyplot.set_size(width-self.WIDTH_PAD, height-self.LABEL_SPACE-self.WIDTH_PAD) @@ -140,7 +143,7 @@ def command(self, action, data): return False - def configure(self, params): + async def configure(self, params): if "plot_type" in params and self.xyplot is None: if params["plot_type"] == "scatter": self.xyplot = ScatterPlot(self, self.INIT_WIDTH, self.INIT_HEIGHT) @@ -153,6 +156,6 @@ def configure(self, params): self.xyplot.set_position(3, self.LABEL_SPACE) if self.xyplot is not None: - self.xyplot.configure(params) + await self.xyplot.configure(params) - super().configure(params) + await super().configure(params) diff --git a/mfp/gui/clutter/processor_element.py b/mfp/gui/clutter/processor_element.py index 66444a5..8575b1a 100644 --- a/mfp/gui/clutter/processor_element.py +++ b/mfp/gui/clutter/processor_element.py @@ -28,10 +28,13 @@ def __init__(self, window, x, y): self.group.set_content(self.texture) self.group.set_reactive(True) - # resize widget whne text gets longer + # resize widget when text gets longer self.handler_id = self.label.signal_listen('text-changed', self.label_changed_cb) - self.set_size(35, 25) - self.move(x, y) + self.width = 35 + self.height = 25 + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) + self.group.set_position(x, y) self.redraw() @@ -50,15 +53,15 @@ def redraw(self): super().redraw() self.texture.invalidate() - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) - def label_changed_cb(self, *args): + async def label_changed_cb(self, *args): newtext = self.label.get_text() if newtext != self.label_text: self.label_text = newtext - self.update() + await self.update() def select(self): super().select() diff --git a/mfp/gui/clutter/slidemeter_element.py b/mfp/gui/clutter/slidemeter_element.py index b1318f2..d16f57b 100644 --- a/mfp/gui/clutter/slidemeter_element.py +++ b/mfp/gui/clutter/slidemeter_element.py @@ -32,17 +32,20 @@ def __init__(self, window, x, y): self.texture = Clutter.Canvas.new() self.texture.connect("draw", self.draw_cb) self.group.set_content(self.texture) - self.group.set_reactive(True) - self.set_size(self.DEFAULT_W, self.DEFAULT_H) - self.move(x, y) + self.width = self.DEFAULT_W + self.height = self.DEFAULT_H + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) + + self.group.set_position(x, y) def redraw(self): self.texture.invalidate() - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) self.texture.invalidate() @@ -206,8 +209,11 @@ def __init__(self, window, x, y): self.group.set_content(self.texture) self.group.set_reactive(True) - self.set_size(self.DEFAULT_W, self.DEFAULT_H) - self.move(x, y) + self.width = self.DEFAULT_W + self.height = self.DEFAULT_H + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) + self.redraw() def p2r(self, r, theta): x = (self.width / 2.0) + r * math.cos(theta) diff --git a/mfp/gui/clutter/text_element.py b/mfp/gui/clutter/text_element.py index 825c7ea..6125b5f 100644 --- a/mfp/gui/clutter/text_element.py +++ b/mfp/gui/clutter/text_element.py @@ -27,9 +27,12 @@ def __init__(self, window, x, y): self.group.set_content(self.texture) self.update_required = True - self.move(x, y) - self.set_size(12, 12) + self.width = 12 + self.height = 12 + self.texture.set_size(self.width, self.height) + self.group.set_size(self.width, self.height) self.group.set_reactive(True) + self.group.set_position(x, y) def redraw(self): self.texture.invalidate() @@ -59,8 +62,8 @@ def draw_cb(self, texture, ct, width, height): ct.stroke() return True - def set_size(self, width, height): - super().set_size(width, height) + async def set_size(self, width, height): + await super().set_size(width, height) self.texture.set_size(width, height) self.texture.invalidate() diff --git a/mfp/gui/clutter/text_widget.py b/mfp/gui/clutter/text_widget.py index 42dd855..8e85679 100644 --- a/mfp/gui/clutter/text_widget.py +++ b/mfp/gui/clutter/text_widget.py @@ -46,8 +46,12 @@ def __init__(self, container): async def delete(self): if self.label: - if hasattr(self.container, 'app_window') and self.label in self.container.app_window.event_sources: + if ( + hasattr(self.container, 'app_window') + and self.label in self.container.app_window.event_sources + ): del self.container.app_window.event_sources[self.label] + self.label.destroy() self.label = None @@ -61,58 +65,96 @@ def hide(self): return self.parent.remove_actor(self.label) def get_width(self): + if not self.label: + return return self.label.get_width() def get_height(self): + if not self.label: + return return self.label.get_height() def get_position(self): + if not self.label: + return return self.label.get_position() def set_position(self, x_pos, y_pos): + if not self.label: + return return self.label.set_position(x_pos, y_pos) def set_activatable(self, val): + if not self.label: + return return self.label.set_activatable(val) def set_single_line_mode(self, val): + if not self.label: + return return self.label.set_single_line_mode(val) def get_cursor_position(self): + if not self.label: + return return self.label.get_cursor_position() def set_cursor_position(self, pos): + if not self.label: + return return self.label.set_cursor_position(pos) if self.label else None def set_cursor_visible(self, visible): + if not self.label: + return return self.label.set_cursor_visible(visible) if self.label else None def set_cursor_color(self, color): + if not self.label: + return return self.label.set_cursor_color(color) def get_text(self): + if not self.label: + return return self.label.get_text() def set_text(self, text): + if not self.label: + return return self.label.set_text(text) if self.label else None def set_markup(self, text): + if not self.label: + return return self.label.set_markup(text) def set_reactive(self, is_reactive): + if not self.label: + return return self.label.set_reactive(is_reactive) def set_color(self, color): + if not self.label: + return return self.label.set_color(color) def set_font_name(self, font_name): + if not self.label: + return return self.label.set_font_name(font_name) def get_property(self, propname): + if not self.label: + return return self.label.get_property(propname) def set_use_markup(self, use_markup): + if not self.label: + return return self.label.set_use_markup(use_markup) if self.label else None def set_selection(self, start, end): + if not self.label: + return return self.label.set_selection(start, end) diff --git a/mfp/gui/clutter/utils.py b/mfp/gui/clutter/utils.py index 3fe933b..d25c406 100644 --- a/mfp/gui/clutter/utils.py +++ b/mfp/gui/clutter/utils.py @@ -1,6 +1,6 @@ from mfp import log -def _callback_wrapper(self, thunk): +def _callback_wrapper(thunk): try: return thunk() except Exception as e: @@ -8,7 +8,7 @@ def _callback_wrapper(self, thunk): log.debug_traceback() return False -def clutter_do_later(self, delay, thunk): +def clutter_do_later(delay, thunk): from gi.repository import GObject - GObject.timeout_add(int(delay), self._callback_wrapper, thunk) + GObject.timeout_add(int(delay), _callback_wrapper, thunk) diff --git a/mfp/gui/clutter/via_element.py b/mfp/gui/clutter/via_element.py index 5d32dfb..57740a2 100644 --- a/mfp/gui/clutter/via_element.py +++ b/mfp/gui/clutter/via_element.py @@ -40,6 +40,7 @@ def __init__(self, window, x, y): txs = self.VIA_SIZE + self.VIA_FUDGE self.texture = Clutter.CairoTexture.new(txs, txs) self.texture.set_size(txs, txs) + self.group.set_size(txs, txs) self.texture.set_surface_size(txs, txs) self.texture.connect("draw", self.draw_cb) @@ -47,6 +48,7 @@ def __init__(self, window, x, y): self.group.set_reactive(True) self.group.add_actor(self.texture) + self.group.set_position(x, y) self.recenter_label() self.redraw() diff --git a/mfp/gui/clutter/xyplot/mark_style.py b/mfp/gui/clutter/xyplot/mark_style.py index 3d6b63c..85b4934 100644 --- a/mfp/gui/clutter/xyplot/mark_style.py +++ b/mfp/gui/clutter/xyplot/mark_style.py @@ -8,7 +8,7 @@ import math from mfp.gui.colordb import ColorDB, RGBAColor - +from mfp import log class MarkStyle: SQRT_3 = 3.0 ** 0.5 @@ -26,12 +26,18 @@ def __init__(self): self.size_elt = None self.alpha_elt = None + def __repr__(self): + return f" ''' -from gi.repository import Clutter -from .xyplot import XYPlot +import os +import numpy +from gi.repository import Clutter +from posix_ipc import SharedMemory from mfp import log from mfp.utils import catchall -from posix_ipc import SharedMemory -from mfp.gui_main import MFPGUI - -import os -import numpy +from .xyplot import XYPlot class ScopePlot (XYPlot): - + FLOAT_SIZE = 4 def __init__(self, element, width, height, samplerate): self.orig_x = 0 self.orig_y = 1 - self.samplerate = samplerate + self.samplerate = samplerate self.buf_info = None self.shm_obj = None - self.colors = [(0, 0, 1, 1), (0, 1, 0, 1), (0, 1, 1, 1), (1, 0, 1, 1), - (1, 1, 0, 1), (1, 0, 0, 1) ] + self.colors = [ + (0, 0, 1, 1), (0, 1, 0, 1), (0, 1, 1, 1), (1, 0, 1, 1), + (1, 1, 0, 1), (1, 0, 0, 1) + ] self.data = [] self.data_start = 0 self.data_end = -1 - self.draw_complete_cb = None + self.draw_complete_cb = None XYPlot.__init__(self, element, width, height) def set_field_origin(self, orig_x, orig_y, redraw=False): self.orig_x = orig_x self.orig_y = orig_y - if redraw: - self.plot.invalidate() + if redraw: + self.plot.invalidate() @catchall - def create_plot(self): + def create_plot(self): self.plot = Clutter.CairoTexture.new(self.plot_w, self.plot_h) self.plot.connect("draw", self.draw_field_cb) self.plot.show() self.plot.invalidate() - def draw_curve_simple(self, ctx, curve): - dataslice = self.data[curve][self.data_start:self.data_end] + dataslice = self.data[curve][self.data_start:self.data_end] xbase = self.data_start * 1000.0 / self.samplerate - xincr = 1000.0 / self.samplerate + xincr = 1000.0 / self.samplerate - ctx.set_source_rgba(*self.colors[curve % len (self.colors)]) + ctx.set_source_rgba(*self.colors[curve % len(self.colors)]) ctx.set_line_width(0.5) - + ctx.move_to(*self.pt2px((xbase, dataslice[0]))) for pt in dataslice: ctx.line_to(*self.pt2px((xbase, pt))) xbase += xincr ctx.stroke() - def draw_curve_minmax(self, ctx, curve): - dataslice = self.data[curve][self.data_start:self.data_end] + def draw_curve_minmax(self, ctx, curve): + dataslice = self.data[curve][self.data_start:self.data_end] xbase = self.data_start * 1000.0 / self.samplerate - xincr = 1000.0 / self.samplerate - dscale = 2*self.plot_w / float(len(dataslice)) - points = [] - ctx.set_source_rgba(*self.colors[curve % len (self.colors)]) + xincr = 1000.0 / self.samplerate + dscale = 2*self.plot_w / float(len(dataslice)) + points = [] + ctx.set_source_rgba(*self.colors[curve % len(self.colors)]) ctx.set_line_width(0.5) - + prevmin = 10000000 prevmax = -10000000 pmin = None - pmax = None + pmax = None ptindex = 0 ptpos = 0 - for pt in dataslice: + for pt in dataslice: if pmin is None or pt < pmin: pmin = pt - if pmax is None or pt > pmax: - pmax = pt - ptpos += dscale - xbase += xincr - if int(ptpos) > ptindex: + if pmax is None or pt > pmax: + pmax = pt + ptpos += dscale + xbase += xincr + if int(ptpos) > ptindex: if ((pmin > prevmin) and (pmin > prevmax)): - pmin = prevmax + pmin = prevmax elif ((pmax < prevmin) and (pmax < prevmax)): pmax = prevmin points.append((xbase, pmin, pmax)) @@ -99,13 +98,13 @@ def draw_curve_minmax(self, ctx, curve): prevmin = pmin prevmax = pmax pmin = None - pmax = None + pmax = None for x, ymin, ymax in points: pmin = self.pt2px((x, ymin)) pmax = self.pt2px((x, ymax)) - if abs(pmin[1] - pmax[1]) < 0.25: + if abs(pmin[1] - pmax[1]) < 0.25: delta = 0.4 - abs(pmin[1] - pmax[1]) if pmin[1] < pmax[1]: delta *= -1.0 @@ -118,14 +117,14 @@ def draw_curve_minmax(self, ctx, curve): @catchall def draw_field_cb(self, texture, ctx, *rest): if not self.data: - return + return texture.clear() ctx.translate(-self.orig_x, -self.orig_y) for curve in range(len(self.data)): - if (len(self.data[curve]) > 2*self.plot_w): + if len(self.data[curve]) > 2*self.plot_w: self.draw_curve_minmax(ctx, curve) - else: + else: self.draw_curve_simple(ctx, curve) if self.draw_complete_cb is not None: self.draw_complete_cb() @@ -136,13 +135,13 @@ def save_style(self): def _grab(self): def offset(channel): return channel * self.buf_info.size * self.FLOAT_SIZE + if self.buf_info is None: return None if self.shm_obj is None: self.shm_obj = SharedMemory(self.buf_info.buf_id) self.data = [] - try: for c in range(self.buf_info.channels): os.lseek(self.shm_obj.fd, offset(c), os.SEEK_SET) @@ -158,7 +157,7 @@ def offset(channel): def command(self, action, data): if action == "buffer": self.buf_info = data - self.shm_obj = None + self.shm_obj = None self.plot.invalidate() elif action == "grab": self._grab() diff --git a/mfp/gui/clutter/xyplot/xyplot.py b/mfp/gui/clutter/xyplot/xyplot.py index 5f82fc1..3847b33 100644 --- a/mfp/gui/clutter/xyplot/xyplot.py +++ b/mfp/gui/clutter/xyplot/xyplot.py @@ -315,5 +315,5 @@ def draw_yaxis_cb(self, texture, ctx, px_min, px_max): ctx.show_text("%.5g" % tick) ctx.restore() - def configure(self, params): + async def configure(self, params): pass diff --git a/mfp/gui/colordb.py b/mfp/gui/colordb.py index c61b308..807f81b 100644 --- a/mfp/gui/colordb.py +++ b/mfp/gui/colordb.py @@ -5,23 +5,31 @@ Copyright (c) 2013 Bill Gribble ''' +from carp.serializer import Serializable +from mfp import log from ..singleton import Singleton from .backend_interfaces import ColorDBBackend -class RGBAColor: - def __init__(self, r, g, b, a): - self.red = r - self.green = g - self.blue = b - self.alpha = a +class RGBAColor(Serializable): + def __init__(self, *, red=0, green=0, blue=0, alpha=0): + self.red = red + self.green = green + self.blue = blue + self.alpha = alpha + super().__init__() + + def to_dict(self): + return dict( + red=self.red, + green=self.green, + blue=self.blue, + alpha=self.alpha + ) @classmethod - def load(self, propdict): - return RGBAColor(propdict.get('red', 0), - propdict.get('green', 0), - propdict.get('blue', 0), - propdict.get('alpha', 0)) + def load(cls, propdict): + return RGBAColor(**propdict) class ColorDB (Singleton): diff --git a/mfp/gui/connection_element.py b/mfp/gui/connection_element.py index 2522587..007eb25 100644 --- a/mfp/gui/connection_element.py +++ b/mfp/gui/connection_element.py @@ -21,6 +21,10 @@ class ConnectionElement(BaseElement): display_type = "connection" LINE_WIDTH = 1.5 + store_attrs = BaseElement.store_attrs + [ + "rotation", "dashed", "obj_1", "port_1", "obj_2", "port_2" + ] + def __init__(self, window, obj_1, port_1, obj_2, port_2, dashed=False): self.obj_1 = obj_1 @@ -39,14 +43,6 @@ def __init__(self, window, obj_1, port_1, obj_2, port_2, dashed=False): px, py = self.obj_1.get_position() super().__init__(window, px, py) - def select(self): - super().select() - self.draw() - - def unselect(self): - super().unselect() - self.draw() - @classmethod def get_factory(cls): return ConnectionElementImpl.get_backend(MFPGUI().appwin.backend_name) diff --git a/mfp/gui/enum_element.py b/mfp/gui/enum_element.py index 3595da4..d20dbb7 100644 --- a/mfp/gui/enum_element.py +++ b/mfp/gui/enum_element.py @@ -70,7 +70,7 @@ def format_value(self, value): value = self.max_value return self.format_str % value - def text_changed_cb(self, *args): + async def text_changed_cb(self, *args): lwidth = self.label.get_property('width') bwidth = self.width @@ -81,7 +81,7 @@ def text_changed_cb(self, *args): new_w = max(35, lwidth + 20) if new_w is not None: - self.set_size(new_w, self.height) + await self.set_size(new_w, self.height) async def create_obj(self): if self.obj_id is None: @@ -120,11 +120,11 @@ async def update_value(self, value): if self.obj_id is not None: await MFPGUI().mfp.send(self.obj_id, 0, self.value) - def update(self): + async def update(self): self.label.set_text(self.format_value(self.value)) self.redraw() - def label_edit_start(self): + async def label_edit_start(self): pass async def label_edit_finish(self, *args): @@ -136,7 +136,7 @@ async def label_edit_finish(self, *args): await MFPGUI().mfp.send(self.obj_id, 0, self.value) self.redraw() - def configure(self, params): + async def configure(self, params): fmt_changed = False val_changed = False @@ -170,7 +170,7 @@ def configure(self, params): if 'height' in params: del params['height'] - BaseElement.configure(self, params) + await super().configure(params) self.redraw() def port_position(self, port_dir, port_num): diff --git a/mfp/gui/input_mode.py b/mfp/gui/input_mode.py index d32661c..5e1c823 100644 --- a/mfp/gui/input_mode.py +++ b/mfp/gui/input_mode.py @@ -14,9 +14,9 @@ def __init__(self, description='', short_description=None): if short_description is not None: self.short_description = short_description else: - self.short_description = self.description - - self.enabled = False + self.short_description = self.description + + self.enabled = False self.default = None self.bindings = {} self.extensions = [] @@ -24,6 +24,10 @@ def __init__(self, description='', short_description=None): self.affinity = 0 self.seqno = None + async def setup(self): + for mode in self.extensions: + await mode.setup() + def extend(self, mode): self.extensions.append(mode) @@ -74,15 +78,15 @@ def lookup(self, keysym): return None def enable(self): - self.enabled = True - for ext in self.extensions: + self.enabled = True + for ext in self.extensions: cb = ext.enable() if inspect.isawaitable(cb): MFPGUI().async_task(cb) def disable(self): - self.enabled = False - for ext in self.extensions: + self.enabled = False + for ext in self.extensions: cb = ext.disable() if inspect.isawaitable(cb): MFPGUI().async_task(cb) diff --git a/mfp/gui/layer.py b/mfp/gui/layer.py index 41666bf..cec8f46 100644 --- a/mfp/gui/layer.py +++ b/mfp/gui/layer.py @@ -22,9 +22,10 @@ def resort(self, obj): self.objects.remove(obj) self.add(obj) - def add(self, obj): + def add(self, obj, container=None): BAD = 1000000 obj.layer = self + obj.layername = self.name def distance(left, right): d1 = ((obj.position_x - left.position_x) ** 2 @@ -61,7 +62,7 @@ def distance(left, right): newloc = distances.index(min(distances)) self.objects[newloc:newloc] = [obj] - self.backend.add(obj) + self.backend.add(obj, container=container) def remove(self, obj): if obj in self.objects: diff --git a/mfp/gui/message_element.py b/mfp/gui/message_element.py index 9bc36b1..b33ca09 100644 --- a/mfp/gui/message_element.py +++ b/mfp/gui/message_element.py @@ -27,6 +27,9 @@ class MessageElement (BaseElement): display_type = "message" proc_type = "message" + label_off_x = 4 + label_off_y = 1 + PORT_TWEAK = 5 def __init__(self, window, x, y): @@ -40,21 +43,20 @@ def __init__(self, window, x, y): # configure label self.label = TextWidget.build(self) - self.label.set_position(4, 1) + self.label.set_position(self.label_off_x, self.label_off_y) self.label.set_color(self.get_color('text-color')) self.label.set_font_name(self.get_fontspec()) - - self.move(x, y) + self.label.set_reactive(False) @classmethod def get_factory(cls): return MessageElementImpl.get_backend(MFPGUI().appwin.backend_name) - def update(self): + async def update(self): self.redraw() self.draw_ports() - def clicked(self, *args): + async def clicked(self, *args): self.clickstate = True if self.obj_id is not None: MFPGUI().async_task(MFPGUI().mfp.send_bang(self.obj_id, 0)) @@ -66,9 +68,9 @@ def unclicked(self): self.redraw() return False - def label_edit_start(self): + async def label_edit_start(self): self.obj_state = self.OBJ_HALFCREATED - self.redraw() + await self.update() async def label_edit_finish(self, widget=None, text=None): if text is not None and text != self.message_text: @@ -78,9 +80,9 @@ async def label_edit_finish(self, widget=None, text=None): if self.obj_id is not None: self.obj_state = self.OBJ_COMPLETE self.send_params() - self.update() + await self.update() - def configure(self, params): + async def configure(self, params): if params.get('value') is not None: self.message_text = repr(params.get('value')) self.label.set_text(self.message_text) @@ -94,8 +96,8 @@ def configure(self, params): if self.obj_state != self.OBJ_COMPLETE and self.obj_id is not None: self.obj_state = self.OBJ_COMPLETE - self.update() - BaseElement.configure(self, params) + await self.update() + await super().configure(params) def port_position(self, port_dir, port_num): # tweak the right input port display to be left of the "kick" @@ -152,7 +154,7 @@ def get_factory(cls): def _make_connections(self): for to in self.target_obj: c = ConnectionElement.build(self.app_window, self, 0, to, self.target_port) - self.app_window.active_layer().add(c) + c.move_to_layer(self.app_window.active_layer()) self.app_window.register(c) self.connections_out.append(c) to.connections_in.append(c) @@ -174,10 +176,10 @@ async def end_edit(self): if self.obj_state == self.OBJ_COMPLETE: await self.delete() - def label_edit_start(self): + async def label_edit_start(self): self.label.set_text(self.message_text) self.label.set_selection(0, len(self.message_text)) - self.redraw() + await self.update() async def label_edit_finish(self, widget=None, text=None): if text is not None: @@ -190,7 +192,7 @@ async def label_edit_finish(self, widget=None, text=None): self.message_text ) for to in self.target_obj: - self.app_window.select(to) + await self.app_window.select(to) self.message_text = None await self.delete() diff --git a/mfp/gui/modes/clickable.py b/mfp/gui/modes/clickable.py index b4195cf..22e6b5c 100644 --- a/mfp/gui/modes/clickable.py +++ b/mfp/gui/modes/clickable.py @@ -2,7 +2,7 @@ ''' clickable.py: Control mode for clickable items (message, bang, toggle) -Copyright (c) 2012 Bill Gribble +Copyright (c) Bill Gribble ''' from ..input_manager import InputManager from ..input_mode import InputMode @@ -48,9 +48,9 @@ def unclick(self): self.widget.unclicked() return False - def quick_click(self): + async def quick_click(self): self.clickstate = True - self.widget.clicked() - self.clickstate = False + await self.widget.clicked() + self.clickstate = False self.widget.unclicked() return True diff --git a/mfp/gui/modes/connection.py b/mfp/gui/modes/connection.py index 7e2d957..a0656f3 100644 --- a/mfp/gui/modes/connection.py +++ b/mfp/gui/modes/connection.py @@ -50,11 +50,11 @@ def __init__(self, window, endpoint, connect_rev=False): self.select_cbid = self.window.signal_listen("select", self.select_cb) self.remove_cbid = self.window.signal_listen("remove", self.remove_cb) - def update_connection(self): + async def update_connection(self): from ..connection_element import ConnectionElement if (self.source_obj is None or self.dest_obj is None): if self.connection: - self.connection.delete() + await self.connection.delete() self.connection = None return True @@ -83,9 +83,9 @@ def update_connection(self): self.connection.port_1 = self.source_port self.connection.port_2 = self.dest_port - self.connection.draw() + await self.connection.draw() - def select(self, obj): + async def select(self, obj): if not obj.editable: return @@ -96,10 +96,10 @@ def select(self, obj): if self.source_obj is not None and obj and self.source_obj != obj: self.dest_obj = obj - self.update_connection() + await self.update_connection() - def select_cb(self, window, signal, obj): - self.select(obj) + async def select_cb(self, window, signal, obj): + await self.select(obj) def remove_cb(self, window, signal, obj): if obj is self.connection: @@ -124,7 +124,7 @@ async def disable(self): await self.connection.delete() self.connection = None - def get_port_key(self): + async def get_port_key(self): def callback(txt): self.set_port_key(int(txt)) @@ -134,11 +134,12 @@ def callback(txt): else: dirspec = "source output" - self.window.get_prompted_input("Enter %s port:" % dirspec, callback) + await self.window.get_prompted_input("Enter %s port:" % dirspec, callback) return True async def make_connection(self): from ..connection_element import ConnectionElement + # are both ends selected? if self.reverse and self.source_obj is None and self.window.selected: self.source_obj = self.window.selected[0] @@ -154,13 +155,13 @@ async def make_connection(self): self.dest_obj.obj_id, self.dest_port ): - c = ConnectionElement.build( - self.window, self.source_obj, self.source_port, - self.dest_obj, self.dest_port - ) - MFPGUI().appwin.register(c) - self.source_obj.connections_out.append(c) - self.dest_obj.connections_in.append(c) + + self.connection.dashed = False + MFPGUI().appwin.register(self.connection) + self.source_obj.connections_out.append(self.connection) + self.dest_obj.connections_in.append(self.connection) + await self.connection.draw() + self.connection = None else: log.debug("ConnectionMode: Cannot make connection") @@ -172,7 +173,7 @@ def abort_connection(self): self.manager.disable_minor_mode(self) return True - def set_port_key(self, portnum): + async def set_port_key(self, portnum): if self.reverse: if (self.source_obj is None and self.window.selected and self.window.selected[0] != self.dest_obj): @@ -191,5 +192,5 @@ def set_port_key(self, portnum): self.dest_port = max(0, min(portnum, self.dest_obj.num_inlets-1)) else: self.source_port = max(0, min(portnum, self.source_obj.num_outlets-1)) - self.update_connection() + await self.update_connection() return True diff --git a/mfp/gui/modes/enum_control.py b/mfp/gui/modes/enum_control.py index da0d708..2162704 100644 --- a/mfp/gui/modes/enum_control.py +++ b/mfp/gui/modes/enum_control.py @@ -23,37 +23,37 @@ def __init__(self, window, element, label): self.bind("C-]", self.set_upper, "Set upper bound on value") self.extend(LabelEditMode(window, element, label)) - def set_upper(self): + async def set_upper(self): def cb(value): if value.lower() == "none": value = None else: value = float(value) self.enum.set_bounds(self.enum.min_value, value) - self.window.get_prompted_input("Number upper bound: ", cb) + await self.window.get_prompted_input("Number upper bound: ", cb) return True - def set_lower(self): + async def set_lower(self): def cb(value): if value.lower() == "none": value = None else: value = float(value) self.enum.set_bounds(value, self.enum.max_value) - self.window.get_prompted_input("Number lower bound: ", cb) + await self.window.get_prompted_input("Number lower bound: ", cb) return True - def add_digit(self): + async def add_digit(self): self.enum.digits += 1 self.enum.format_update() - self.enum.update() + await self.enum.update() return True - def del_digit(self): + async def del_digit(self): if self.enum.digits > 0: self.enum.digits -= 1 self.enum.format_update() - self.enum.update() + await self.enum.update() return True def end_edits(self): diff --git a/mfp/gui/modes/global_mode.py b/mfp/gui/modes/global_mode.py index f1625c9..3ddd315 100644 --- a/mfp/gui/modes/global_mode.py +++ b/mfp/gui/modes/global_mode.py @@ -31,9 +31,6 @@ def __init__(self, window): self.drag_last_y = None self.drag_target = None - self.previous_console_position = 0 - self.next_tree_position = 1 - InputMode.__init__(self, "Global input bindings") # global keybindings @@ -93,39 +90,12 @@ def inspect(self): from flopsy import Store Store.show_inspector(event_loop=MFPGUI().async_task.asyncio_loop) - # FIXME this is clutter-specific - def toggle_console(self): - alloc = self.window.backend.content_console_pane.get_allocation() - oldpos = self.window.backend.content_console_pane.get_position() - - console_visible = oldpos < (alloc.height - 2) - if console_visible: - next_pos = alloc.height - self.previous_console_position = oldpos - else: - next_pos = self.previous_console_position - - self.window.backend.content_console_pane.set_position(next_pos) - - return False - - # FIXME this is clutter-specific - def toggle_tree(self): - from mfp.gui.clutter.utils import clutter_do_later - oldpos = self.window.backend.tree_canvas_pane.get_position() - - self.window.backend.tree_canvas_pane.set_position(self.next_tree_position) - self.next_tree_position = oldpos - - # KLUDGE! - clutter_do_later(100, self._refresh) - + async def toggle_console(self): + await self.window.signal_emit("toggle-console") return False - # FIXME this is clutter-specific - def _refresh(self): - oldpos = self.window.backend.content_console_pane.get_position() - self.window.backend.content_console_pane.set_position(oldpos - 1) + async def toggle_tree(self): + await self.window.signal_emit("toggle-info-panel") return False async def force_reset(self): @@ -161,7 +131,7 @@ async def hover(self, details): pass return False - def save_file(self): + async def save_file(self): import os.path patch = self.window.selected_patch if patch.last_filename is None: @@ -169,7 +139,7 @@ def save_file(self): else: default_filename = patch.last_filename - def cb(fname): + async def cb(fname): if fname: patch.last_filename = fname if fname != default_filename: @@ -177,25 +147,26 @@ def cb(fname): parts = os.path.splitext(basefile) newname = parts[0] patch.obj_name = newname - MFPGUI().mfp.rename_obj.sync(patch.obj_id, newname) - patch.send_params() + await MFPGUI().mfp.rename_obj(patch.obj_id, newname) + prms = patch.synced_params() + await MFPGUI().mfp.set_params(patch.obj_id, prms) self.window.refresh(patch) - MFPGUI().async_task(MFPGUI().mfp.save_file(patch.obj_name, fname)) - self.window.get_prompted_input("File name to save: ", cb, default_filename) + await MFPGUI().mfp.save_file(patch.obj_name, fname) + await self.window.get_prompted_input("File name to save: ", cb, default_filename) - def save_as_lv2(self): + async def save_as_lv2(self): patch = self.window.selected_patch default_plugname = 'mfp_' + patch.obj_name - def cb(plugname): + async def cb(plugname): if plugname: - MFPGUI().mfp.save_lv2.sync(patch.obj_name, plugname) - self.window.get_prompted_input("Plugin name to save: ", cb, default_plugname) + await MFPGUI().mfp.save_lv2(patch.obj_name, plugname) + await self.window.get_prompted_input("Plugin name to save: ", cb, default_plugname) - def open_file(self): - def cb(fname): - MFPGUI().async_task(MFPGUI().mfp.open_file(fname)) - self.window.get_prompted_input("File name to load: ", cb) + async def open_file(self): + async def cb(fname): + await MFPGUI().mfp.open_file(fname) + await self.window.get_prompted_input("File name to load: ", cb) def drag_start(self): self.drag_started = True @@ -227,34 +198,23 @@ def drag_end(self): return True async def selbox_start(self, select_mode): - px = self.manager.pointer_x py = self.manager.pointer_y enclosed = [] selection_corners = [(px, py), (px+1, py), (px+1, py+1), (px, py+1)] - for obj in self.window.selected_layer.objects: - if obj.parent_id and MFPGUI().recall(obj.parent_id).parent_id: - continue - corners = obj.corners() - - if corners and collision_check(selection_corners, corners): - enclosed.append(obj) - if enclosed: - self.manager.pointer_obj = enclosed[0] - if select_mode is None: if self.manager.pointer_obj is not None: if self.manager.pointer_obj not in self.window.selected: - # log.debug(f"[selbox] selecting pointer_obj {self.manager.pointer_obj}") await self.window.unselect_all() await self.window.select(self.manager.pointer_obj) raise InputManager.InputNeedsRequeue() - # log.debug(f"[selbox] was None, pointer_obj={self.manager.pointer_obj}, selected={self.window.selected}") if self.allow_selection_drag: self.selection_drag_started = True + for obj in self.window.selected: + if obj.editable and obj.display_type != 'connection': + obj.drag_start() else: - # log.debug(f"[selbox] pointer_obj={self.manager.pointer_obj}, selected={self.window.selected}") await self.window.unselect_all() self.selbox_started = True elif select_mode is True: @@ -289,7 +249,7 @@ async def selbox_motion(self, select_mode): if self.selection_drag_started: for obj in self.window.selected: if obj.editable and obj.display_type != 'connection': - obj.drag(dx, dy) + await obj.drag(dx, dy) return True enclosed = self.window.show_selection_box( @@ -323,10 +283,11 @@ async def selbox_motion(self, select_mode): return True - def selbox_end(self): - #log.debug("[selbox_end] got button-up") + async def selbox_end(self): if self.selection_drag_started: for obj in self.window.selected: + if obj.editable and obj.display_type != 'connection': + await obj.drag_end() obj.send_params() self.selbox_started = False self.selection_drag_started = False @@ -343,7 +304,7 @@ async def close_confirm(answer): p = self.window.selected_patch if await MFPGUI().mfp.has_unsaved_changes(p.obj_id): - self.window.get_prompted_input("Patch has unsaved changes. Close anyway? [yN]", + await self.window.get_prompted_input("Patch has unsaved changes. Close anyway? [yN]", close_confirm, '') else: await self.window.patch_close() @@ -361,7 +322,7 @@ def quit_confirm(answer): if await MFPGUI().mfp.has_unsaved_changes(p): clean = False if not clean: - self.window.get_prompted_input( + await self.window.get_prompted_input( "There are patches with unsaved changes. Quit anyway? [yN]", quit_confirm, '' diff --git a/mfp/gui/modes/label_edit.py b/mfp/gui/modes/label_edit.py index f19c41f..43a791a 100644 --- a/mfp/gui/modes/label_edit.py +++ b/mfp/gui/modes/label_edit.py @@ -102,7 +102,8 @@ def __init__(self, window, element, label, multiline=False, markup=False, self.bind(None, self.insert_text, "Insert text") - inittxt = self.element.label_edit_start() + async def setup(self): + inittxt = await self.element.label_edit_start() if inittxt: self.text = inittxt @@ -112,6 +113,8 @@ def __init__(self, window, element, label, multiline=False, markup=False, self.update_cursor() self.set_selection(0, len(self.text)) + await super().setup() + def cut(self): sel = self.text[self.selection_start:self.selection_end] self.window.clipboard_set(sel) diff --git a/mfp/gui/modes/slider.py b/mfp/gui/modes/slider.py index 09e9d38..1972e4d 100644 --- a/mfp/gui/modes/slider.py +++ b/mfp/gui/modes/slider.py @@ -107,63 +107,63 @@ def __init__(self, window, element, descrip): self.bind("C-]", self.set_hi, "Enter upper bound") self.bind("C-|", self.set_zero, "Enter zero point") - def set_low(self): - def hud_cb(value): + async def set_low(self): + async def hud_cb(value): if value is not None: - self.slider.set_bounds(float(value), self.slider.max_value) - self.window.get_prompted_input("Slider lower bound: ", hud_cb) + await self.slider.set_bounds(float(value), self.slider.max_value) + await self.window.get_prompted_input("Slider lower bound: ", hud_cb) return True - def set_hi(self): - def hud_cb(value): + async def set_hi(self): + async def hud_cb(value): if value is not None: - self.slider.set_bounds(self.slider.min_value, float(value)) - self.window.get_prompted_input("Slider upper bound: ", hud_cb) + await self.slider.set_bounds(self.slider.min_value, float(value)) + await self.window.get_prompted_input("Slider upper bound: ", hud_cb) return True - def set_zero(self): - def hud_cb(value): + async def set_zero(self): + async def hud_cb(value): if value is not None: if value != "None": - self.slider.set_zeropoint(float(value)) + await self.slider.set_zeropoint(float(value)) else: - self.slider.set_zeropoint(None) - self.window.get_prompted_input("Slider zero point: ", hud_cb) + await self.slider.set_zeropoint(None) + await self.window.get_prompted_input("Slider zero point: ", hud_cb) return True - def toggle_scale(self): - self.slider.set_show_scale(not self.slider.show_scale) - self.slider.update() + async def toggle_scale(self): + await self.slider.set_show_scale(not self.slider.show_scale) + await self.slider.update() self.slider.send_params() return True - def toggle_orient(self): + async def toggle_orient(self): if self.slider.orientation == self.slider.HORIZONTAL: self.slider.set_orientation(self.slider.VERTICAL) else: self.slider.set_orientation(self.slider.HORIZONTAL) - self.slider.update() + await self.slider.update() self.slider.send_params() return True - def toggle_direction(self): + async def toggle_direction(self): if self.slider.direction == self.slider.POSITIVE: self.slider.direction = self.slider.NEGATIVE else: self.slider.direction = self.slider.POSITIVE - self.slider.update() + await self.slider.update() self.slider.send_params() return True - def toggle_side(self): + async def toggle_side(self): if self.slider.scale_position == self.slider.RIGHT: self.slider.scale_position = self.slider.LEFT else: self.slider.scale_position = self.slider.RIGHT - self.slider.update() + await self.slider.update() self.slider.send_params() return True diff --git a/mfp/gui/patch_display.py b/mfp/gui/patch_display.py index 5200f72..2070e8d 100644 --- a/mfp/gui/patch_display.py +++ b/mfp/gui/patch_display.py @@ -1,9 +1,10 @@ #! /usr/bin/env python ''' patch_display.py -PatchDisplay class capturing display information for a patch +PatchDisplay class captures display information for a patch: +a subset of the layers and objects in the app window -Copyright (c) 2012 Bill Gribble +Copyright (c) Bill Gribble ''' from ..gui_main import MFPGUI @@ -42,7 +43,7 @@ def get_factory(cls): def build(cls, *args, **kwargs): return cls.get_factory()(*args, **kwargs) - def update(self): + async def update(self): pass def has_scope(self, scope_name): @@ -58,7 +59,7 @@ def send_params(self, **extras): for k, v in extras.items(): prms[k] = v if self.obj_id is not None: - MFPGUI().async_task(MFPGUI().mfp.set_params.sync(self.obj_id, prms)) + MFPGUI().async_task(MFPGUI().mfp.set_params(self.obj_id, prms)) def find_layer(self, layer): for ll in self.layers: @@ -66,7 +67,7 @@ def find_layer(self, layer): return ll return None - def configure(self, params): + async def configure(self, params): self.num_inlets = params.get("num_inlets") self.num_outlets = params.get("num_outlets") self.dsp_inlets = params.get("dsp_inlets") @@ -118,6 +119,3 @@ async def delete(self): to_delete = self.obj_id self.obj_id = None await MFPGUI().mfp.delete(to_delete) - - def command(self, action, data): - pass diff --git a/mfp/gui/plot_element.py b/mfp/gui/plot_element.py index d2f870b..76235cc 100644 --- a/mfp/gui/plot_element.py +++ b/mfp/gui/plot_element.py @@ -42,8 +42,10 @@ def __init__(self, window, x, y, params=None): super().__init__(window, x, y) - self.param_list.extend(['x_min', 'x_max', 'y_min', 'y_max', - 'plot_style', 'plot_type']) + self.param_list.extend([ + 'x_min', 'x_max', 'y_min', 'y_max', + 'plot_style', 'plot_type' + ]) # display bounds self.x_min = 0.0 @@ -67,13 +69,13 @@ def __init__(self, window, x, y, params=None): def get_factory(cls): return PlotElementImpl.get_backend(MFPGUI().appwin.backend_name) - def update(self): + async def update(self): self.draw_ports() def get_label(self): return self.label - def label_edit_start(self): + async def label_edit_start(self): # FIXME set label to editing style pass @@ -86,7 +88,6 @@ async def label_edit_finish(self, *args): if len(parts) > 1: self.obj_args = parts[1] - log.debug("PlotElement: type=%s, args=%s" % (self.obj_type, self.obj_args)) self.proc_type = self.obj_type await self.create(self.proc_type, self.obj_args) @@ -97,7 +98,6 @@ async def label_edit_finish(self, *args): self.draw_ports() # FIXME set label to non-editing style - self.update() def label_changed_cb(self, *args): pass @@ -105,7 +105,7 @@ def label_changed_cb(self, *args): async def make_edit_mode(self): return LabelEditMode(self.app_window, self, self.label) - def configure(self, params): + async def configure(self, params): if self.obj_args is None: self.label.set_text("%s" % (self.obj_type,)) else: @@ -118,4 +118,4 @@ def configure(self, params): self.set_bounds(x_min, y_min, x_max, y_max) - super().configure(params) + await super().configure(params) diff --git a/mfp/gui/processor_element.py b/mfp/gui/processor_element.py index 4cd6b15..e25f92d 100644 --- a/mfp/gui/processor_element.py +++ b/mfp/gui/processor_element.py @@ -66,7 +66,7 @@ def __init__(self, window, x, y, params=None): def get_factory(cls): return ProcessorElementImpl.get_backend(MFPGUI().appwin.backend_name) - def update(self): + async def update(self): if self.show_label or self.obj_state == self.OBJ_HALFCREATED: label_width = self.label.get_property('width') + 14 else: @@ -81,17 +81,17 @@ def update(self): new_w = max(35, port_width, label_width, box_width) - self.set_size(new_w, self.texture.get_property('height')) + await self.set_size(new_w, self.texture.get_property('height')) self.redraw() def get_label(self): return self.label - def label_edit_start(self): + async def label_edit_start(self): self.obj_state = self.OBJ_HALFCREATED if not self.show_label: self.label.show() - self.update() + await self.update() async def label_edit_finish(self, widget, text=None): if text is not None: @@ -114,12 +114,12 @@ async def label_edit_finish(self, widget, text=None): if not self.show_label: self.label.hide() - self.update() + await self.update() async def make_edit_mode(self): return LabelEditMode(self.app_window, self, self.label) - def configure(self, params): + async def configure(self, params): if self.obj_args is None: self.label.set_text("%s" % (self.obj_type,)) else: @@ -148,16 +148,16 @@ def configure(self, params): params["width"] = max(self.width, params.get("export_w") or 0) params["height"] = max(self.height, (params.get("export_h") or 0) + labelheight) - super().configure(params) + await super().configure(params) if self.obj_id is not None and self.obj_state != self.OBJ_COMPLETE: self.obj_state = self.OBJ_COMPLETE if self.export_created: - MFPGUI().mfp.create_export_gui.task(self.obj_id) + await MFPGUI().mfp.create_export_gui(self.obj_id) need_update = True if "debug" in params: need_update = True if need_update: - self.update() + await self.update() diff --git a/mfp/gui/prompter.py b/mfp/gui/prompter.py index a32a8b1..ed50904 100644 --- a/mfp/gui/prompter.py +++ b/mfp/gui/prompter.py @@ -18,13 +18,13 @@ def __init__(self, window): self.current_callback = None self.mode = None - def get_input(self, prompt, callback, default): + async def get_input(self, prompt, callback, default): if self.mode is None: - self._begin(prompt, callback, default) + await self._begin(prompt, callback, default) else: self.queue.append([prompt, callback, default]) - def _begin(self, prompt, callback, default): + async def _begin(self, prompt, callback, default): self.current_prompt = prompt self.current_callback = callback self.window.hud_set_prompt(prompt, default) @@ -32,9 +32,10 @@ def _begin(self, prompt, callback, default): self.backend, self, self.backend.hud_prompt_input, mode_desc="Prompted input" ) + await self.mode.setup() self.window.input_mgr.enable_minor_mode(self.mode) - def label_edit_start(self): + async def label_edit_start(self): pass async def label_edit_finish(self, widget, text): @@ -56,6 +57,6 @@ async def end_edit(self): if len(self.queue): nextitem = self.queue[0] self.queue = self.queue[1:] - self._begin(nextitem[0], nextitem[1], nextitem[2]) + await self._begin(nextitem[0], nextitem[1], nextitem[2]) diff --git a/mfp/gui/slidemeter_element.py b/mfp/gui/slidemeter_element.py index 09aa6e8..8f8085a 100644 --- a/mfp/gui/slidemeter_element.py +++ b/mfp/gui/slidemeter_element.py @@ -22,7 +22,12 @@ class SlideMeterElement (BaseElement): Can be output-only or interactive Scale can be dB or linear ''' - + extra_params = [ + 'min_value', 'max_value', 'show_scale', 'scale', + 'scale_font_size', 'scale_position', 'orientation', + 'zeropoint' + ] + store_attrs = BaseElement.store_attrs + extra_params display_type = "slidemeter" proc_type = "slidemeter" @@ -31,8 +36,6 @@ class SlideMeterElement (BaseElement): 'meter-color': 'default-alt-fill-color' } - DEFAULT_W = 25 - DEFAULT_H = 100 SCALE_SPACE = 30 TICK_SPACE = 14 TICK_LEN = 5 @@ -45,8 +48,8 @@ class SlideMeterElement (BaseElement): def __init__(self, window, x, y): super().__init__(window, x, y) - self.param_list.extend(['min_value', 'max_value', 'show_scale', 'scale', - 'scale_position', 'orientation', 'zeropoint']) + self.param_list.extend([*self.extra_params]) + # parameters controlling display self.value = 0.0 self.min_value = 0.0 @@ -56,6 +59,7 @@ def __init__(self, window, x, y): self.slider_enable = True self.scale = ticks.LinearScale() self.scale_position = self.LEFT + self.scale_font_size = 7 self.orientation = self.VERTICAL self.zeropoint = None @@ -100,29 +104,29 @@ def update_value(self, value): self.redraw() MFPGUI().async_task(MFPGUI().mfp.send(self.obj_id, 0, self.value)) - def set_orientation(self, orient): + async def set_orientation(self, orient): if orient != self.orientation: - self.set_size(self.height, self.width) - self.orientation = orient + await self.set_size(self.height, self.width) + await self.dispatch(self.action(self.SET_ORIENTATION, value=orient)) - def set_show_scale(self, show_scale): + async def set_show_scale(self, show_scale): if show_scale == self.show_scale: return if show_scale: self.show_scale = True if self.orientation & self.HORIZONTAL: - self.set_size(self.get_width(), self.get_height() + self.SCALE_SPACE) + await self.set_size(self.get_width(), self.get_height() + self.SCALE_SPACE) else: - self.set_size(self.get_width() + self.SCALE_SPACE, self.get_height()) + await self.set_size(self.get_width() + self.SCALE_SPACE, self.get_height()) else: self.show_scale = False if self.orientation & self.HORIZONTAL: - self.set_size(self.get_width(), self.get_height() - self.SCALE_SPACE) + await self.set_size(self.get_width(), self.get_height() - self.SCALE_SPACE) else: - self.set_size(self.get_width() - self.SCALE_SPACE, self.get_height()) + await self.set_size(self.get_width() - self.SCALE_SPACE, self.get_height()) - def set_bounds(self, min_val, max_val): + async def set_bounds(self, min_val, max_val): self.max_value = max_val self.min_value = min_val self.scale.set_bounds(self.min_value, self.max_value) @@ -140,15 +144,15 @@ def set_bounds(self, min_val, max_val): MFPGUI().async_task(MFPGUI().mfp.send(self.obj_id, 0, self.value)) self.scale_ticks = None - self.update() + await self.update() self.send_params() - def set_zeropoint(self, zp): + async def set_zeropoint(self, zp): self.zeropoint = zp - self.update() + await self.update() self.send_params() - def configure(self, params): + async def configure(self, params): changes = False v = params.get("orientation") @@ -213,7 +217,7 @@ def configure(self, params): if rescale: self.scale.set_bounds(self.min_value, self.max_value) self.scale_ticks = None - self.update() + await self.update() v = params.get("value") if v is not None: @@ -229,7 +233,7 @@ def configure(self, params): if dr is not None: self.dial_radius = dr - BaseElement.configure(self, params) + await super().configure(params) if changes: self.redraw() @@ -258,7 +262,11 @@ def make_control_mode(self): class FaderElementImpl(ABC, BackendInterface): pass + class FaderElement(SlideMeterElement): + DEFAULT_W = 20 + DEFAULT_H = 100 + @classmethod def get_factory(cls): return FaderElementImpl.get_backend(MFPGUI().appwin.backend_name) @@ -289,6 +297,7 @@ class DialElement(SlideMeterElement): DEFAULT_W = 50 DEFAULT_H = 50 DEFAULT_R = 24 + BAR_WIDTH = 0.7 THETA_MIN = 0.65*math.pi THETA_MAX = 0.35*math.pi @@ -307,17 +316,22 @@ def get_factory(cls): def set_orientation(self, orient): pass - def set_show_scale(self, show_scale): + async def set_show_scale(self, show_scale): if show_scale == self.show_scale: return if show_scale: self.show_scale = True - self.set_size(2*self.dial_radius + 2.0 + 7*self.scale_font_size, - 2*self.dial_radius + 2.0 + 3*self.scale_font_size) + await self.set_size( + 2*self.dial_radius + 2.0 + 7*self.scale_font_size, + 2*self.dial_radius + 2.0 + 3*self.scale_font_size + ) else: self.show_scale = False - self.set_size(2*self.dial_radius + 2.0, 2*self.dial_radius + 2.0) + await self.set_size( + 2*self.dial_radius + 2.0, + 2*self.dial_radius + 2.0 + ) async def make_edit_mode(self): if self.obj_id is None: diff --git a/mfp/gui/text_element.py b/mfp/gui/text_element.py index 926912a..f47d1c6 100644 --- a/mfp/gui/text_element.py +++ b/mfp/gui/text_element.py @@ -55,10 +55,12 @@ def __init__(self, window, x, y): def get_factory(cls): return TextElementImpl.get_backend(MFPGUI().appwin.backend_name) - def update(self): + async def update(self): if not self.get_style('canvas-size'): - self.set_size(self.label.get_width() + 2*self.ELBOW_ROOM, - self.label.get_height() + self.ELBOW_ROOM) + await self.set_size( + self.label.get_width() + 2*self.ELBOW_ROOM, + self.label.get_height() + self.ELBOW_ROOM + ) self.redraw() self.draw_ports() @@ -66,7 +68,7 @@ def draw_ports(self): if self.selected: super().draw_ports() - def label_edit_start(self): + async def label_edit_start(self): return self.value async def label_edit_finish(self, widget, new_text, aborted=False): @@ -78,21 +80,21 @@ async def label_edit_finish(self, widget, new_text, aborted=False): self.value = new_text self.set_text() await MFPGUI().mfp.send(self.obj_id, 0, self.value) - self.update() + await self.update() async def end_edit(self): await BaseElement.end_edit(self) self.set_text() - def text_changed_cb(self, *args): - self.update() + async def text_changed_cb(self, *args): + await self.update() - def clicked(self): + async def clicked(self): def newtext(txt): self.value = txt or '' self.set_text() if self.selected and self.clickchange: - self.app_window.get_prompted_input("New text:", newtext, self.value) + await self.app_window.get_prompted_input("New text:", newtext, self.value) return True def set_text(self): @@ -127,7 +129,7 @@ async def make_edit_mode(self): def make_control_mode(self): return ClickableControlMode(self.app_window, self, "Change text", 'A-') - def configure(self, params): + async def configure(self, params): if params.get('value') is not None: new_text = params.get('value') if new_text != self.value: @@ -148,13 +150,14 @@ def configure(self, params): params['width'] = newsize[0] params['height'] = newsize[1] - BaseElement.configure(self, params) + await super().configure(params) + if newsize: - self.set_size(*newsize) + await self.set_size(*newsize) if 'style' in params: newstyle = params['style'] if 'font-face' in newstyle or 'font-size' in newstyle: self.label.set_font_name(self.get_fontspec()) - self.update() + await self.update() diff --git a/mfp/gui/via_element.py b/mfp/gui/via_element.py index fc341d0..239c114 100644 --- a/mfp/gui/via_element.py +++ b/mfp/gui/via_element.py @@ -40,12 +40,9 @@ def __init__(self, window, x, y): self.label.set_color(self.get_color('text-color')) self.label.set_font_name(self.get_fontspec()) self.label.signal_listen('text-changed', self.text_changed_cb) - - self.move(x, y) - self.set_size( - self.VIA_SIZE + 2 * self.VIA_FUDGE, - self.VIA_SIZE + self.LABEL_HEIGHT + self.LABEL_FUDGE + 2 * self.VIA_FUDGE - ) + + self.width = self.VIA_SIZE + 2 * self.VIA_FUDGE + self.height = self.VIA_SIZE + self.LABEL_HEIGHT + self.LABEL_FUDGE + 2 * self.VIA_FUDGE def text_changed_cb(self, *args): self.recenter_label() @@ -67,7 +64,7 @@ async def create_obj(self, label_text): (name, port) = self.parse_label(label_text) await self.create(self.proc_type, '"%s",%s' % (name, port)) - def label_edit_start(self, *args): + async def label_edit_start(self, *args): pass async def label_edit_finish(self, *args): @@ -78,11 +75,11 @@ async def label_edit_finish(self, *args): await self.create_obj(t) self.recenter_label() - def configure(self, params): + async def configure(self, params): self.label_text = params.get("label_text", "") self.label.set_text(self.label_text) self.recenter_label() - BaseElement.configure(self, params) + await super().configure(params) def port_position(self, port_dir, port_num): # vias connect to the center of the texture @@ -102,7 +99,6 @@ def unselect(self): async def make_edit_mode(self): return LabelEditMode(self.app_window, self, self.label) - class SendViaElementImpl(ABC, BackendInterface): @abstractmethod def redraw(self): diff --git a/mfp/gui_command.py b/mfp/gui_command.py index 3f79caf..98ed906 100644 --- a/mfp/gui_command.py +++ b/mfp/gui_command.py @@ -46,18 +46,18 @@ def command(self, obj_id, action, args): obj = MFPGUI().recall(obj_id) obj.command(action, args) - def configure(self, obj_id, params=None, **kwparams): + async def configure(self, obj_id, params=None, **kwparams): from .gui_main import MFPGUI obj = MFPGUI().recall(obj_id) if params is not None: - obj.configure(params) + await obj.configure(params) else: prms = obj.synced_params() for k, v in kwparams.items(): prms[k] = v - obj.configure(prms) + await obj.configure(prms) - def create(self, obj_type, obj_args, obj_id, parent_id, params): + async def create(self, obj_type, obj_args, obj_id, parent_id, params): from .gui_main import MFPGUI from .gui.patch_display import PatchDisplay from .gui.base_element import BaseElement @@ -112,6 +112,7 @@ def create(self, obj_type, obj_args, obj_id, parent_id, params): layer = parent.find_layer(params["layername"]) if not layer: layer = MFPGUI().appwin.active_layer() + o.container = layer layer.add(o) elif isinstance(parent, BaseElement): # FIXME: don't hardcode GOP offsets @@ -119,23 +120,21 @@ def create(self, obj_type, obj_args, obj_id, parent_id, params): log.debug( f"_create: parent {parent.scope.name}.{parent.name} has no export_x\n", ) - xpos = params.get("position_x", 0) - parent.export_x + 2 - ypos = params.get("position_y", 0) - parent.export_y + 20 - o.move(xpos, ypos) o.editable = False - parent.layer.add(o) + o.container = parent + parent.layer.add(o, container=parent) - o.configure(params) + await o.configure(params) MFPGUI().appwin.register(o) else: - o.configure(params) + await o.configure(params) MFPGUI().remember(o) MFPGUI().appwin.refresh(o) - o.update() - MFPGUI().async_task(MFPGUI().appwin.signal_emit("created", o)) + await o.update() + await MFPGUI().appwin.signal_emit("created", o) - def connect(self, obj_1_id, obj_1_port, obj_2_id, obj_2_port): + async def connect(self, obj_1_id, obj_1_port, obj_2_id, obj_2_port): from .gui_main import MFPGUI from .gui.connection_element import ConnectionElement from .gui.patch_display import PatchDisplay @@ -161,6 +160,7 @@ def connect(self, obj_1_id, obj_1_port, obj_2_id, obj_2_port): MFPGUI().appwin.register(c) obj_1.connections_out.append(c) obj_2.connections_in.append(c) + await c.update() async def delete(self, obj_id): from .gui_main import MFPGUI diff --git a/mfp/gui_main.py b/mfp/gui_main.py index 72b76ce..5da8b24 100644 --- a/mfp/gui_main.py +++ b/mfp/gui_main.py @@ -64,7 +64,6 @@ def recall(self, obj_id): return self.objects.get(obj_id) def finish(self): - from gi.repository import Gtk if self.debug: import yappi yappi.stop() @@ -76,8 +75,6 @@ def finish(self): if self.appwin: self.appwin.quit() self.appwin = None - # FIXME clutter - Gtk.main_quit() def setup_default_colors(): diff --git a/mfp/mfp_command.py b/mfp/mfp_command.py index cab5ab8..7c2fd4d 100644 --- a/mfp/mfp_command.py +++ b/mfp/mfp_command.py @@ -4,6 +4,7 @@ Copyright (c) Bill Gribble """ +import json from carp.service import apiclass, noresp from mfp import log @@ -26,11 +27,11 @@ async def create(self, objtype, initargs, patch_name, scope_name, obj_name): return None return obj.gui_params - def create_export_gui(self, obj_id): + async def create_export_gui(self, obj_id): from .mfp_app import MFPApp obj = MFPApp().recall(obj_id) if isinstance(obj, Patch): - obj.create_export_gui() + await obj.create_export_gui() return True return False @@ -56,7 +57,7 @@ async def dsp_response(self, obj_id, resp_type, resp_value): from .mfp_app import MFPApp obj = MFPApp().recall(obj_id) if isinstance(obj, Processor): - await obj.send((resp_type, resp_value), -1) + await obj.send((resp_type, json.loads(resp_value)), -1) @noresp async def send_bang(self, obj_id, port): diff --git a/mfp/patch.py b/mfp/patch.py index 11e8d4e..ce17ceb 100644 --- a/mfp/patch.py +++ b/mfp/patch.py @@ -332,7 +332,7 @@ def dsp_outlet(self, outlet): ############################ @classmethod - def register_file(klass, filename): + def register_file(cls, filename): from .mfp_app import MFPApp async def factory(init_type, init_args, patch, scope, name, context=None): @@ -354,7 +354,7 @@ async def create_gui(self, **kwargs): if MFPApp().no_gui: return False - elif self.gui_created: + if self.gui_created: return True # create the basic element info @@ -392,15 +392,13 @@ async def delete_gui(self): if not self.gui_created: return True - for oid, obj in self.objects.items(): + for _, obj in self.objects.items(): obj.gui_created = False - #obj.delete_gui() await Processor.delete_gui(self) return True async def has_unsaved_changes(self): - import difflib import copy if self.file_origin: oldjson = open(self.file_origin, 'r').read() @@ -412,7 +410,7 @@ async def has_unsaved_changes(self): newjson = await self.json_serialize() self.gui_params = saved_gui - cdiff = difflib.context_diff(oldjson.split('\n'), newjson.split('\n')) + # cdiff = difflib.context_diff(oldjson.split('\n'), newjson.split('\n')) if oldjson != newjson: log.warning("Unsaved changes in '%s'" % self.name, "(%s)" % self.file_origin) @@ -431,7 +429,7 @@ async def save_file(self, filename): if os.path.isfile(filename): os.rename(filename, filename+'~') - + log.debug(f"Saving patch to {filename}") with open(filename, "w") as savefile: savefile.write(await self.json_serialize()) diff --git a/mfp/patch_json.py b/mfp/patch_json.py index b8522e2..3b57252 100644 --- a/mfp/patch_json.py +++ b/mfp/patch_json.py @@ -73,7 +73,8 @@ def extended_decoder_hook(saved): ctor = ExtendedEncoder.TYPES.get(tname) if ctor: if hasattr(ctor, 'load'): - return ctor.load(tdict) + loaded = ctor.load(tdict) + return loaded else: return _dumb_load(ctor, tdict) return saved diff --git a/mfp/processor.py b/mfp/processor.py index 93003dd..383eb03 100644 --- a/mfp/processor.py +++ b/mfp/processor.py @@ -101,10 +101,12 @@ def __init__(self, inlets, outlets, init_type, init_args, patch, scope, name): scopename = scope.name if scope else "__patch__" - defaults = dict(obj_id=self.obj_id, - initargs=self.init_args, display_type=self.display_type, - scope=scopename, - num_inlets=inlets, num_outlets=outlets) + defaults = dict( + obj_id=self.obj_id, + initargs=self.init_args, display_type=self.display_type, + scope=scopename, + num_inlets=inlets, num_outlets=outlets + ) for k, v in defaults.items(): if k not in self.gui_params: @@ -223,10 +225,12 @@ def tooltip(self, port_dir=None, port_num=None, details=False): paths = MFPApp().midi_mgr._filt2paths(self.midi_filters) lines.append(' MIDI handlers:') for p in paths: - lines.append(' Chan: %s, Type: %s, Number: %s' - % (p[2] if p[2] is not None else "All", - p[1] if p[1] is not None else "All", - p[3] if p[3] is not None else "All")) + lines.append( + ' Chan: %s, Type: %s, Number: %s' + % (p[2] if p[2] is not None else "All", + p[1] if p[1] is not None else "All", + p[3] if p[3] is not None else "All") + ) return '\n'.join(lines) def tooltip_extra(self): @@ -293,10 +297,16 @@ def rescope(self, new_scope): self.assign(self.patch, self.patch.scopes.get(new_scope), self.name) def _osc_handler(self, path, args, types, src, data): + from .mfp_app import MFPApp + if types[0] == 's': - self.send(self.patch.parse_obj(args[0])) + MFPApp().async_task( + self.send(self.patch.parse_obj(args[0])) + ) else: - self.send(args[0]) + MFPApp().async_task( + self.send(args[0]) + ) # return 0 means completely handled, nonzero keep trying return 0 @@ -582,34 +592,34 @@ async def connect(self, outlet, target, inlet, show_gui=True): % (target.name, target.obj_id, inlet, len(target.inlets))) return False - # is this a DSP connection? - if outlet in self.dsp_outlets: - if inlet not in target.dsp_inlets: - if isinstance(target, Patch): - Patch.task_nibbler.add_task( - lambda args: Processor.connect(*args), 20, - [self, outlet, target, inlet, show_gui] - ) - log.warning("'%s' (obj_id %d) inlet is not DSP, waiting" - % (target.name, target.obj_id)) - return True - log.warning( - "Error: Can't connect DSP out %s of '%s' to non-DSP in %s of '%s'" - % (outlet, self.name, inlet, target.name)) - return False - - out_obj, out_outlet = self.dsp_outlet(outlet) - in_obj, in_inlet = target.dsp_inlet(inlet) - if out_obj and in_obj: - await out_obj.connect(out_outlet, in_obj._id, in_inlet) - else: - log.warning("Trying to find DSP objects, failed", type(self), self.name, - type(target), target.name, - inlet, "-->", in_obj, ",", outlet, "-->", out_obj) - try: existing = self.connections_out[outlet] if (target, inlet) not in existing: + # is this a DSP connection? + if outlet in self.dsp_outlets: + if inlet not in target.dsp_inlets: + if isinstance(target, Patch): + Patch.task_nibbler.add_task( + lambda args: Processor.connect(*args), 20, + [self, outlet, target, inlet, show_gui] + ) + log.warning("'%s' (obj_id %d) inlet is not DSP, waiting" + % (target.name, target.obj_id)) + return True + log.warning( + "Error: Can't connect DSP out %s of '%s' to non-DSP in %s of '%s'" + % (outlet, self.name, inlet, target.name)) + return False + + out_obj, out_outlet = self.dsp_outlet(outlet) + in_obj, in_inlet = target.dsp_inlet(inlet) + if out_obj and in_obj: + await out_obj.connect(out_outlet, in_obj._id, in_inlet) + else: + log.warning("Trying to find DSP objects, failed", type(self), self.name, + type(target), target.name, + inlet, "-->", in_obj, ",", outlet, "-->", out_obj) + existing.append((target, inlet)) except Exception: # this can happen normally in a creation race, don't @@ -1058,7 +1068,6 @@ def load(self, prms): # special handling for gui_params gp = prms.get('gui_params') - for k, v in gp.items(): self.gui_params[k] = v self.gui_params['scope'] = self.scope.name diff --git a/mfpdsp/builtin_buffer.c b/mfpdsp/builtin_buffer.c index fbeb966..367aace 100644 --- a/mfpdsp/builtin_buffer.c +++ b/mfpdsp/builtin_buffer.c @@ -344,8 +344,11 @@ shared_buffer_alloc(buf_info * buf) snprintf(buf->shm_id, 64, "/mfp_buffer_%05d_%06d_%06d", pid, (int)tv.tv_sec, (int)tv.tv_usec); - buf->shm_fd = shm_open(buf->shm_id, O_RDWR|O_CREAT, S_IRWXU); + buf->shm_fd = shm_open(buf->shm_id, O_RDWR|O_CREAT, S_IRWXU); + if (buf->shm_fd < 0) { + mfp_log_debug("shm_open() failed... %d (%s)\n", buf->shm_fd, strerror(errno)); + } if(buf->buf_ptr != NULL) { munmap(buf->buf_ptr, buf->buf_size); buf->buf_ptr = NULL; @@ -354,7 +357,7 @@ shared_buffer_alloc(buf_info * buf) buf->buf_size = size; buf->buf_ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, buf->shm_fd, 0); if (buf->buf_ptr == NULL) { - printf("mmap() failed... %d (%s)\n", buf->shm_fd, strerror(errno)); + mfp_log_debug("mmap() failed... %d (%s)\n", buf->shm_fd, strerror(errno)); } } diff --git a/mfpdsp/builtin_stepseq.c b/mfpdsp/builtin_stepseq.c index 842e3f2..f6c4a99 100644 --- a/mfpdsp/builtin_stepseq.c +++ b/mfpdsp/builtin_stepseq.c @@ -37,6 +37,9 @@ typedef struct { * steps: ordered array of value/trigger/slur * threshold: thresh for input clock * trigger_len: frames for output trigger + * signal outputs: + * [0] sequenced value + * [1] trigger on change */ static int diff --git a/wscript b/wscript index 96922ff..88ae2eb 100644 --- a/wscript +++ b/wscript @@ -2,6 +2,7 @@ from __future__ import print_function +from waflib import Utils from waflib.Configure import conf from waflib.Build import BuildContext, InstallContext, CleanContext, CFG_FILES import waflib @@ -81,6 +82,9 @@ def fix_virtualenv(ctxt, *args, **kwargs): "echo 'if echo $LD_LIBRARY_PATH | grep -vq :%s/lib64:' >> activate.edited" % ctxt.env.PREFIX, "echo 'then export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s/lib64:' >> activate.edited" % ctxt.env.PREFIX, "echo 'fi' >> activate.edited", + "echo 'if echo $LD_LIBRARY_PATH | grep -vq :%s/lib:' >> activate.edited" % ctxt.env.PREFIX, + "echo 'then export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s/lib:' >> activate.edited" % ctxt.env.PREFIX, + "echo 'fi' >> activate.edited", "mv activate.edited virtual/bin/activate", "touch %s" % targetfile ] @@ -517,8 +521,19 @@ def build(bld): use=['mfpdsp']) bld.add_group() - #bld(features="install_wheels") - #bld.add_group() + bld.install_files( + "share/mfp/icons/hicolor/scalable/actions/", + "mfp.svg" + ) + + if bld.cmd == "install": + desktop_dir = Utils.subst_vars("${PREFIX}/share/mfp", bld.env) + desktop_filename = "mfp.desktop" + desktop_template = Utils.readf(desktop_filename) + desktop_content = Utils.subst_vars(desktop_template, bld.env) + if not os.path.exists(desktop_dir): + os.makedirs(desktop_dir) + Utils.writef(f"{desktop_dir}/{desktop_filename}", desktop_content) # must make virtualenv "relocatable" after all packages added bld.fix_virtualenv()