Reorganize top-level directories with clearer naming convention

app -> app-desktop-macos, presets -> app-presets, server -> remote-server,
daw-config-reaper -> osc-config-daw, plugin-reaper-realearn -> plugin-reaper-relearn.
Updated run.py and presets.py path references accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Paul Lipscomb
2026-07-15 17:51:05 -04:00
parent e58f06d9fa
commit 7ecc718f5d
2256 changed files with 11 additions and 5 deletions
@@ -0,0 +1,165 @@
= Design decisions
:toc:
:experimental:
This document sheds a bit light about why some features in ReaLearn exist and why they were built as they are.
Just in case you are interested.
[[decision-advanced-settings-via-yaml]]
== Advanced settings via YAML
The link:https://docs.helgoboss.org/realearn/user-interface/mapping-panel/advanced-settings-dialog.html[Advanced settings dialog] makes it possible to configure a few advanced mapping settings by entering text in the YAML configuration language.
Deciding for textual configuration and YAML in particular was a conscious decision with the goal to provide a developer-friendly framework for rapidly extending ReaLearn with advanced features that don't urgently need a graphical user interface.
Why ask the user to enter text instead of providing a convenient graphical user interface?::
* That's mostly a tradeoff due to the fact that my time available for developing ReaLearn is limited.
* It's much work to develop a graphical user interface for every feature.
In fact, programming the user interface often takes most of the time whereas implementing the actual logic is not that much effort.
* It's true that some sorts of functionality really benefit from having a fancy graphical user interface.
But there's also functionality for which having it is not too important, e.g. functionality that is of configurational nature and not used that often.
* Also, one of ReaLearn's goals is to give power users and programmers extra powers.
Textual configuration can be more powerful in many situations once the user knows how to go about it.
Why YAML?::
* YAML has the advantage of being popular among programmers, widely supported, highly structured and relatively well readable/writable by both humans and machines.
* Many link:https://en.wikipedia.org/wiki/Text_editor[text editors] offer built-in support for editing YAML.
* Makes it easy to provide data for even very complex features.
Why not a scripting language?::
* Using a scripting language would spoil any future possibility to add a graphical user interface on top of some of the functionality.
* It wouldn't allow ReaLearn to apply future optimizations and improvements.
ReaLearn is rather declarative in nature and a scripting language would destroy this quality.
* It's hard to come up with a stable and good API.
* It's harder to use than a configuration language.
Why don't you save the text, just the structure?::
* Mostly because saving just the structure makes the entered data become a natural part of ReaLearn's main preset format (JSON).
* Once we would start saving the actual text, it would be hard to go back.
== Lua(u) as main scripting language
=== Introduction
ReaLearn supports scripting in various places:
- *MIDI scripts:* Lua or EEL (Lua support more powerful)
- *Feedback scripts (for MIDI or OSC):* Lua only
- *Control transformations:* EEL only (because must be real-time capable)
- *Import/export:* JSON or Lua (Lua obviously more powerful)
- *Dynamic conditional activation:* Expression language or EEL
- *Target-based conditional activation:* Expression language
- *Dynamic expressions:* Expression language
=== Advantages of Lua
As can be seen, Lua is our main scripting language for stuff that doesn't need to run in real-time.
Here's why:
* Lua is easily embeddable (this is a must, and it rules out most other mainstream languages)
* Lua is popular and widely-used (important, rules out exotic or new languages such as Rhai or Gluon)
* Lua has nice features that make it very suitable for building data structures and even DSLs (our main use case):
** Operator overloading (rules out JavaScript/TypeScript)
** Ability to skip parentheses when passing function argument (rules out JavaScript/TypeScript)
** Really usable multi-line strings
* Doesn't increase the size of the binary very much (nice to have)
* It can be quite fast (not important for import/export but very helpful when it comes to e.g. MIDI or feedback scripts)
* REAPER power users already know Lua because it's also REAPER's primary scripting language (not strictly necessary but certainly helps because REAPER users are usually not developers, so switching languages might be a big effort for them)
=== Ruled out alternatives
Some languages that were considered but ruled out.
Here they are, along with the most important reasons why there were ruled out:
* JavaScript/TypeScript: no operator overloading, not possible to skip parentheses when passing function argument, also much harder to embed
** In general, I was very much in favor of JavaScript/TypeScript because it's so widespread and the tooling is perfect.
But turns out Lua is actually better suited for our main use case of creating large data structures for import/export.
Surprise!
** Assembling mappings is an example where operator overloading is really nice: `name("Scroll up") + shift_or_sustain + button("col1/stop") + feedback_disabled() + turbo() + scroll_vertically(-1)`
** Also, embedding it is very hard.
Yes, there is TypeScriptToLua, but the TypeScriptToLua compiler is also written in JavaScript.
We need a solution that runs 100% in ReaLearn without external pre-processing.
* Python: too heavy-weight, also harder to embed and slower
* Wren: doesn't seem to be active anymore, maybe a bit too exotic (looks exciting though)
* Gluon: too exotic
* Dyon: too exotic
* Rhai: too exotic
* Mun: hard/impossible to embed, not mature enough
* Rust: hard/impossible to embed, not easy enough
* WASM: just embedding a WASM runtime wouldn't help because it's just for running WASM bytecode but not producing the bytecode, which would require a language-to-WASM compiler, which again brings up the question of which scripting language
- AssemblyScript: interesting because TypeScript-like and operator overloading, but ultimately looks too hard to embed because it needs a WASM runtime and I need to make it itself run within that runtime, also things like operator overloading don't have IDE support
- Haxe: direct embedding doesn't seem to be possible, so would only be interesting for transpiling outside Helgobox
=== Disadvantages of Lua
Despite its many advantages, there are also a few really annoying things about Lua:
* No static typing
* String concatenation is ugly
* No distinction between maps an arrays (just tables)
* Really spartan standard library
* No strong conventions
=== How to tackle the remaining disadvantages
There are some interesting projects out there that seek to address Lua's pain points.
==== Teal
Teal is a statically typed Lua dialect transpiled to Lua.
Pros:
- Compiles to Lua
Cons:
- Language server can't auto-complete fields in table literals.
Not at all.
- The type system is less elaborate than that of Luau.
Unions are not powerful enough, e.g. two tables can't be part of a union, which also excludes tagged unions.
We have a lot of tagged unions.
- Types are required, no structural typing
- Needs an additional compilation step to be loadable into the VM
==== LuaLS
LuaLS is a Lua language server with type checking capabilities.
Pros:
- Types are optional, structural typing
- Can auto-complete not-yet typed fields in table literals
- Works without needing another language
- Seems to allow dots in type names.
Which would be nice for something like `Target.TrackVolume` instead of `Target_TrackVolume`.
Cons:
- No type deduction based on tagged union discriminator
- Typing in comments only, feels like patchwork and is not really intuitive
==== Luau
Luau is a Lua fork with optional static typing.
Pros:
- Types are optional, structural typing
- Type refinement based on tagged union discriminator
- Looks like the most elaborate type system of all candidates
- Promise of backward compatible changes
- Really nice usability improvements over normal Lua, such as string interpolation and easier iterating
Cons:
- link:https://github.com/luau-lang/luau/issues/685[Can't auto-complete not-yet typed fields in table literals]
- Type system still has its flaws, especially when it comes to intersections.
On the other hand, the other candidates don't even try something as advanced as intersections.
- Not sure about using a fork
- Typing too structural?
It doesn't spit out the type name anymore after assignment.
==== Verdict
Luau
@@ -0,0 +1,695 @@
<svg width="1251pt" height="642pt" viewBox="0.00 0.00 1251.00 642.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 638)">
<title>components</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-638 1247,-638 1247,4 -4,4"></polygon>
<g id="clust1" class="cluster level-1">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="158,-79 158,-626 1040,-626 1040,-79 158,-79"></polygon>
<text text-anchor="middle" x="599" y="-610.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<g id="clust2" class="cluster level-2">
<title>cluster_instance</title>
<polygon fill="none" stroke="black" points="166,-166 166,-595 808,-595 808,-166 166,-166"></polygon>
<text text-anchor="middle" x="487" y="-579.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance</text>
</g>
<!-- MidiInputDevice -->
<g id="node1" class="node">
<title>MidiInputDevice</title>
<polygon fill="none" stroke="black" points="110,-300 0,-300 0,-264 110,-264 110,-300"></polygon>
<text text-anchor="middle" x="55" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiInputDevice</text>
</g>
<!-- RealearnAudioHook -->
<g id="node9" class="node layer-processing">
<title>RealearnAudioHook</title>
<polygon fill="none" stroke="black" points="332.5,-123 203.5,-123 203.5,-87 332.5,-87 332.5,-123"></polygon>
<text text-anchor="middle" x="268" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnAudioHook</text>
</g>
<!-- MidiInputDevice&#45;&gt;RealearnAudioHook -->
<g id="edge17" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>MidiInputDevice-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M51.56,-263.66C46.81,-234.2 42.11,-174.31 74,-141 90.41,-123.86 145.94,-115.02 193.41,-110.52"></path>
<polygon fill="black" stroke="black" points="193.75,-114 203.4,-109.62 193.13,-107.03 193.75,-114"></polygon>
<text text-anchor="middle" x="169" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- MidiOutputDevice -->
<g id="node2" class="node">
<title>MidiOutputDevice</title>
<polygon fill="none" stroke="black" points="327.5,-36 208.5,-36 208.5,0 327.5,0 327.5,-36"></polygon>
<text text-anchor="middle" x="268" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiOutputDevice</text>
</g>
<!-- FxChain -->
<g id="node3" class="node">
<title>FxChain</title>
<polygon fill="none" stroke="black" points="1115.5,-564 1050.5,-564 1050.5,-528 1115.5,-528 1115.5,-564"></polygon>
<text text-anchor="middle" x="1083" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">FxChain</text>
</g>
<!-- RealearnPlugin -->
<g id="node14" class="node layer-infrastructure">
<title>RealearnPlugin</title>
<polygon fill="none" stroke="black" points="368.5,-477 267.5,-477 267.5,-441 368.5,-441 368.5,-477"></polygon>
<text text-anchor="middle" x="318" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnPlugin</text>
</g>
<!-- FxChain&#45;&gt;RealearnPlugin -->
<g id="edge13" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>FxChain-&gt;RealearnPlugin</title>
<path fill="none" stroke="black" d="M1050.07,-529.76C1048.04,-529.1 1046.01,-528.5 1044,-528 944.52,-503.17 916.21,-518.19 814,-510 635.31,-495.67 589.75,-500.31 412,-477 401.17,-475.58 389.7,-473.77 378.62,-471.85"></path>
<polygon fill="black" stroke="black" points="379.05,-468.38 368.59,-470.08 377.83,-475.27 379.05,-468.38"></polygon>
<text text-anchor="middle" x="900.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- Reaper -->
<g id="node4" class="node">
<title>Reaper</title>
<polygon fill="none" stroke="black" points="1188.5,-564 1133.5,-564 1133.5,-528 1188.5,-528 1188.5,-564"></polygon>
<text text-anchor="middle" x="1161" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Reaper</text>
</g>
<!-- RealearnControlSurfaceMiddleware -->
<g id="node8" class="node layer-processing">
<title>RealearnControlSurfaceMiddleware</title>
<polygon fill="none" stroke="black" points="1028,-477 816,-477 816,-441 1028,-441 1028,-477"></polygon>
<text text-anchor="middle" x="922" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnControlSurfaceMiddleware</text>
</g>
<!-- Reaper&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge7" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>Reaper-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M1133.24,-531.49C1130.47,-530.27 1127.69,-529.08 1125,-528 1080.08,-509.94 1028.31,-492.66 988.3,-480.03"></path>
<polygon fill="black" stroke="black" points="989.24,-476.66 978.65,-477.01 987.15,-483.34 989.24,-476.66"></polygon>
<text text-anchor="middle" x="1141.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER change events</text>
</g>
<!-- App -->
<g id="node5" class="node layer-infrastructure">
<title>App</title>
<polygon fill="none" stroke="black" points="1032,-564 978,-564 978,-528 1032,-528 1032,-564"></polygon>
<text text-anchor="middle" x="1005" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">App</text>
</g>
<!-- Server -->
<g id="node6" class="node layer-infrastructure">
<title>Server</title>
<polygon fill="none" stroke="black" points="960,-564 906,-564 906,-528 960,-528 960,-564"></polygon>
<text text-anchor="middle" x="933" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Server</text>
</g>
<!-- Backbone -->
<g id="node7" class="node layer-processing">
<title>Backbone</title>
<polygon fill="none" stroke="black" points="887.5,-564 816.5,-564 816.5,-528 887.5,-528 887.5,-564"></polygon>
<text text-anchor="middle" x="852" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Backbone</text>
</g>
<!-- MainProcessor -->
<g id="node19" class="node layer-processing">
<title>MainProcessor</title>
<polygon fill="none" stroke="black" points="693,-390 549,-390 549,-174 693,-174 693,-390"></polygon>
<text text-anchor="middle" x="621" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MainProcessor</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge9" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M815.77,-441.43C814.5,-441.28 813.25,-441.14 812,-441 783,-437.77 569.91,-444.33 550,-423 535.7,-407.68 536.4,-388.93 544.37,-370.19"></path>
<polygon fill="black" stroke="black" points="547.61,-371.53 548.84,-361.01 541.32,-368.47 547.61,-371.53"></polygon>
<text text-anchor="middle" x="652" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER and instance change events</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge10" class="edge com-sync dir-control type-osc role-realtime-osc">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M822.13,-440.94C805.29,-436.27 788.32,-430.39 773,-423 763.31,-418.33 763.42,-413.19 754,-408 732.95,-396.4 722.45,-404.12 703,-390 702.36,-389.54 701.72,-389.07 701.09,-388.59"></path>
<polygon fill="black" stroke="black" points="702.98,-385.62 693,-382.07 698.59,-391.07 702.98,-385.62"></polygon>
<text text-anchor="middle" x="827" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC control events</text>
</g>
<!-- RealearnAudioHook&#45;&gt;MidiOutputDevice -->
<g id="edge20" class="edge com-sync dir-feedback type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;MidiOutputDevice</title>
<path fill="none" stroke="black" d="M268,-86.8C268,-75.16 268,-59.55 268,-46.24"></path>
<polygon fill="black" stroke="black" points="271.5,-46.18 268,-36.18 264.5,-46.18 271.5,-46.18"></polygon>
<text text-anchor="middle" x="372" y="-57.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- RealTimeProcessor -->
<g id="node18" class="node layer-processing">
<title>RealTimeProcessor</title>
<polygon fill="none" stroke="black" points="340,-390 196,-390 196,-174 340,-174 340,-390"></polygon>
<text text-anchor="middle" x="268" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealTimeProcessor</text>
</g>
<!-- RealearnAudioHook&#45;&gt;RealTimeProcessor -->
<g id="edge18" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M268,-123.23C268,-133.69 268,-148.05 268,-163.88"></path>
<polygon fill="black" stroke="black" points="264.5,-163.91 268,-173.91 271.5,-163.91 264.5,-163.91"></polygon>
<text text-anchor="middle" x="363" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- OscOutputDevice -->
<g id="node10" class="node layer-processing">
<title>OscOutputDevice</title>
<polygon fill="none" stroke="black" points="769.5,-123 654.5,-123 654.5,-87 769.5,-87 769.5,-123"></polygon>
<text text-anchor="middle" x="712" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OscOutputDevice</text>
</g>
<!-- infrastructure_layer -->
<!-- application_layer -->
<!-- infrastructure_layer&#45;&gt;application_layer -->
<!-- processing_layer -->
<!-- application_layer&#45;&gt;processing_layer -->
<!-- RealearnPlugin&#45;&gt;RealTimeProcessor -->
<g id="edge14" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>RealearnPlugin-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M267.41,-452.8C248.41,-448.11 228.62,-439.33 217,-423 211.94,-415.89 209.1,-408.22 207.98,-400.26"></path>
<polygon fill="black" stroke="black" points="211.46,-399.85 207.45,-390.05 204.47,-400.21 211.46,-399.85"></polygon>
<text text-anchor="middle" x="303.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- RealearnUi -->
<g id="node15" class="node layer-infrastructure">
<title>RealearnUi</title>
<polygon fill="none" stroke="black" points="489,-564 411,-564 411,-528 489,-528 489,-564"></polygon>
<text text-anchor="middle" x="450" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnUi</text>
</g>
<!-- Session -->
<g id="node16" class="node layer-management">
<title>Session</title>
<polygon fill="none" stroke="black" points="479,-477 421,-477 421,-441 479,-441 479,-477"></polygon>
<text text-anchor="middle" x="450" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Session</text>
</g>
<!-- Session&#45;&gt;RealearnUi -->
<g id="edge6" class="edge com-sync role-notify">
<title>Session-&gt;RealearnUi</title>
<path fill="none" stroke="black" d="M450,-477.18C450,-488.81 450,-504.42 450,-517.73"></path>
<polygon fill="black" stroke="black" points="446.5,-517.8 450,-527.8 453.5,-517.8 446.5,-517.8"></polygon>
<text text-anchor="middle" x="468.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- Session&#45;&gt;MainProcessor -->
<g id="edge3" class="edge com-async role-sync-data">
<title>Session-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M425.12,-440.9C414.75,-431.55 406.46,-419.56 413,-408 440.07,-360.14 493.6,-328.59 539.57,-309.16"></path>
<polygon fill="black" stroke="black" points="541.03,-312.35 548.96,-305.32 538.38,-305.87 541.03,-312.35"></polygon>
<text text-anchor="middle" x="440" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- InstanceState -->
<g id="node17" class="node layer-processing">
<title>InstanceState</title>
<polygon fill="none" stroke="black" points="800.5,-300 711.5,-300 711.5,-264 800.5,-264 800.5,-300"></polygon>
<text text-anchor="middle" x="756" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">InstanceState</text>
</g>
<!-- InstanceState&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge8" class="edge com-async dir-feedback type-general role-realtime-general">
<title>InstanceState-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M775.77,-300.29C801.97,-323.6 849.05,-366.94 885,-408 891.69,-415.64 898.45,-424.41 904.34,-432.45"></path>
<polygon fill="black" stroke="black" points="901.65,-434.72 910.33,-440.8 907.34,-430.63 901.65,-434.72"></polygon>
<text text-anchor="middle" x="958.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance change events</text>
</g>
<!-- RealTimeProcessor&#45;&gt;FxChain -->
<g id="edge16" class="edge com-sync dir-feedback type-midi-fx role-realtime-midi-fx">
<title>RealTimeProcessor-&gt;FxChain</title>
<path fill="none" stroke="black" d="M340.09,-319.15C393.75,-344.1 469.58,-375.33 540,-390 567.27,-395.68 1021.36,-388.25 1041,-408 1062.63,-429.75 1049.69,-447.31 1042,-477 1039.7,-485.86 1034.3,-486.14 1032,-495 1030.33,-501.45 1028.89,-504.1 1032,-510 1034.6,-514.93 1038.23,-519.3 1042.38,-523.13"></path>
<polygon fill="black" stroke="black" points="1040.3,-525.95 1050.3,-529.46 1044.67,-520.48 1040.3,-525.95"></polygon>
<text text-anchor="middle" x="1147.5" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
<!-- RealTimeProcessor&#45;&gt;MainProcessor -->
<g id="edge12" class="edge com-async dir-control type-midi-general role-realtime-midi-general">
<title>RealTimeProcessor-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M340.29,-282C397.87,-282 478.51,-282 538.6,-282"></path>
<polygon fill="black" stroke="black" points="538.81,-285.5 548.81,-282 538.81,-278.5 538.81,-285.5"></polygon>
<text text-anchor="middle" x="444.5" y="-288.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Control values (from MIDI events)</text>
</g>
<!-- MainProcessor&#45;&gt;RealearnAudioHook -->
<g id="edge19" class="edge com-async dir-feedback type-midi-device role-realtime-midi-device">
<title>MainProcessor-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M549,-218.05C507.06,-181.5 461.84,-142.36 459,-141 422.88,-123.69 379.14,-114.9 342.63,-110.46"></path>
<polygon fill="black" stroke="black" points="342.87,-106.97 332.54,-109.32 342.08,-113.92 342.87,-106.97"></polygon>
<text text-anchor="middle" x="578" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- MainProcessor&#45;&gt;OscOutputDevice -->
<g id="edge11" class="edge com-async dir-feedback type-osc role-realtime-osc">
<title>MainProcessor-&gt;OscOutputDevice</title>
<path fill="none" stroke="black" d="M680.91,-173.94C684.04,-167.9 687.09,-161.89 690,-156 693.73,-148.47 697.51,-140.16 700.86,-132.52"></path>
<polygon fill="black" stroke="black" points="704.09,-133.87 704.84,-123.3 697.66,-131.09 704.09,-133.87"></polygon>
<text text-anchor="middle" x="756.5" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC feedback events</text>
</g>
<!-- MainProcessor&#45;&gt;Session -->
<g id="edge5" class="edge com-sync role-notify">
<title>MainProcessor-&gt;Session</title>
<path fill="none" stroke="black" d="M548.86,-347.61C528.87,-366.49 507.57,-387.56 489,-408 481.97,-415.74 474.78,-424.62 468.53,-432.73"></path>
<polygon fill="black" stroke="black" points="465.65,-430.74 462.39,-440.82 471.22,-434.97 465.65,-430.74"></polygon>
<text text-anchor="middle" x="507.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge4" class="edge com-async role-sync-data">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.72,-298.95C545.95,-299.35 543.2,-299.7 540.5,-300 500.74,-304.39 404.05,-304.67 350.41,-299.96"></path>
<polygon fill="black" stroke="black" points="350.58,-296.46 340.28,-298.95 349.89,-303.42 350.58,-296.46"></polygon>
<text text-anchor="middle" x="444.5" y="-309.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge15" class="edge com-async dir-feedback type-midi-fx role-realtime-midi-fx">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.71,-265.11C545.77,-264.69 542.86,-264.31 540,-264 500.45,-259.66 404.27,-259.39 350.46,-264.1"></path>
<polygon fill="black" stroke="black" points="349.9,-260.64 340.29,-265.11 350.59,-267.61 349.9,-260.64"></polygon>
<text text-anchor="middle" x="444.5" y="-267.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style><style>.edge{visibility:hidden;}</style><style>.edge.role-sync-data{visibility:visible;}</style><style>.edge.role-notify{visibility:visible;}</style></svg>

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,695 @@
<svg width="1251pt" height="642pt" viewBox="0.00 0.00 1251.00 642.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 638)">
<title>components</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-638 1247,-638 1247,4 -4,4"></polygon>
<g id="clust1" class="cluster level-1">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="158,-79 158,-626 1040,-626 1040,-79 158,-79"></polygon>
<text text-anchor="middle" x="599" y="-610.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<g id="clust2" class="cluster level-2">
<title>cluster_instance</title>
<polygon fill="none" stroke="black" points="166,-166 166,-595 808,-595 808,-166 166,-166"></polygon>
<text text-anchor="middle" x="487" y="-579.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance</text>
</g>
<!-- MidiInputDevice -->
<g id="node1" class="node">
<title>MidiInputDevice</title>
<polygon fill="none" stroke="black" points="110,-300 0,-300 0,-264 110,-264 110,-300"></polygon>
<text text-anchor="middle" x="55" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiInputDevice</text>
</g>
<!-- RealearnAudioHook -->
<g id="node9" class="node layer-processing">
<title>RealearnAudioHook</title>
<polygon fill="none" stroke="black" points="332.5,-123 203.5,-123 203.5,-87 332.5,-87 332.5,-123"></polygon>
<text text-anchor="middle" x="268" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnAudioHook</text>
</g>
<!-- MidiInputDevice&#45;&gt;RealearnAudioHook -->
<g id="edge17" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>MidiInputDevice-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M51.56,-263.66C46.81,-234.2 42.11,-174.31 74,-141 90.41,-123.86 145.94,-115.02 193.41,-110.52"></path>
<polygon fill="black" stroke="black" points="193.75,-114 203.4,-109.62 193.13,-107.03 193.75,-114"></polygon>
<text text-anchor="middle" x="169" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- MidiOutputDevice -->
<g id="node2" class="node">
<title>MidiOutputDevice</title>
<polygon fill="none" stroke="black" points="327.5,-36 208.5,-36 208.5,0 327.5,0 327.5,-36"></polygon>
<text text-anchor="middle" x="268" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiOutputDevice</text>
</g>
<!-- FxChain -->
<g id="node3" class="node">
<title>FxChain</title>
<polygon fill="none" stroke="black" points="1115.5,-564 1050.5,-564 1050.5,-528 1115.5,-528 1115.5,-564"></polygon>
<text text-anchor="middle" x="1083" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">FxChain</text>
</g>
<!-- RealearnPlugin -->
<g id="node14" class="node layer-infrastructure">
<title>RealearnPlugin</title>
<polygon fill="none" stroke="black" points="368.5,-477 267.5,-477 267.5,-441 368.5,-441 368.5,-477"></polygon>
<text text-anchor="middle" x="318" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnPlugin</text>
</g>
<!-- FxChain&#45;&gt;RealearnPlugin -->
<g id="edge13" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>FxChain-&gt;RealearnPlugin</title>
<path fill="none" stroke="black" d="M1050.07,-529.76C1048.04,-529.1 1046.01,-528.5 1044,-528 944.52,-503.17 916.21,-518.19 814,-510 635.31,-495.67 589.75,-500.31 412,-477 401.17,-475.58 389.7,-473.77 378.62,-471.85"></path>
<polygon fill="black" stroke="black" points="379.05,-468.38 368.59,-470.08 377.83,-475.27 379.05,-468.38"></polygon>
<text text-anchor="middle" x="900.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- Reaper -->
<g id="node4" class="node">
<title>Reaper</title>
<polygon fill="none" stroke="black" points="1188.5,-564 1133.5,-564 1133.5,-528 1188.5,-528 1188.5,-564"></polygon>
<text text-anchor="middle" x="1161" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Reaper</text>
</g>
<!-- RealearnControlSurfaceMiddleware -->
<g id="node8" class="node layer-processing">
<title>RealearnControlSurfaceMiddleware</title>
<polygon fill="none" stroke="black" points="1028,-477 816,-477 816,-441 1028,-441 1028,-477"></polygon>
<text text-anchor="middle" x="922" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnControlSurfaceMiddleware</text>
</g>
<!-- Reaper&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge7" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>Reaper-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M1133.24,-531.49C1130.47,-530.27 1127.69,-529.08 1125,-528 1080.08,-509.94 1028.31,-492.66 988.3,-480.03"></path>
<polygon fill="black" stroke="black" points="989.24,-476.66 978.65,-477.01 987.15,-483.34 989.24,-476.66"></polygon>
<text text-anchor="middle" x="1141.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER change events</text>
</g>
<!-- App -->
<g id="node5" class="node layer-infrastructure">
<title>App</title>
<polygon fill="none" stroke="black" points="1032,-564 978,-564 978,-528 1032,-528 1032,-564"></polygon>
<text text-anchor="middle" x="1005" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">App</text>
</g>
<!-- Server -->
<g id="node6" class="node layer-infrastructure">
<title>Server</title>
<polygon fill="none" stroke="black" points="960,-564 906,-564 906,-528 960,-528 960,-564"></polygon>
<text text-anchor="middle" x="933" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Server</text>
</g>
<!-- Backbone -->
<g id="node7" class="node layer-processing">
<title>Backbone</title>
<polygon fill="none" stroke="black" points="887.5,-564 816.5,-564 816.5,-528 887.5,-528 887.5,-564"></polygon>
<text text-anchor="middle" x="852" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Backbone</text>
</g>
<!-- MainProcessor -->
<g id="node19" class="node layer-processing">
<title>MainProcessor</title>
<polygon fill="none" stroke="black" points="693,-390 549,-390 549,-174 693,-174 693,-390"></polygon>
<text text-anchor="middle" x="621" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MainProcessor</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge9" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M815.77,-441.43C814.5,-441.28 813.25,-441.14 812,-441 783,-437.77 569.91,-444.33 550,-423 535.7,-407.68 536.4,-388.93 544.37,-370.19"></path>
<polygon fill="black" stroke="black" points="547.61,-371.53 548.84,-361.01 541.32,-368.47 547.61,-371.53"></polygon>
<text text-anchor="middle" x="652" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER and instance change events</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge10" class="edge com-sync dir-control type-osc role-realtime-osc">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M822.13,-440.94C805.29,-436.27 788.32,-430.39 773,-423 763.31,-418.33 763.42,-413.19 754,-408 732.95,-396.4 722.45,-404.12 703,-390 702.36,-389.54 701.72,-389.07 701.09,-388.59"></path>
<polygon fill="black" stroke="black" points="702.98,-385.62 693,-382.07 698.59,-391.07 702.98,-385.62"></polygon>
<text text-anchor="middle" x="827" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC control events</text>
</g>
<!-- RealearnAudioHook&#45;&gt;MidiOutputDevice -->
<g id="edge20" class="edge com-sync dir-feedback type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;MidiOutputDevice</title>
<path fill="none" stroke="black" d="M268,-86.8C268,-75.16 268,-59.55 268,-46.24"></path>
<polygon fill="black" stroke="black" points="271.5,-46.18 268,-36.18 264.5,-46.18 271.5,-46.18"></polygon>
<text text-anchor="middle" x="372" y="-57.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- RealTimeProcessor -->
<g id="node18" class="node layer-processing">
<title>RealTimeProcessor</title>
<polygon fill="none" stroke="black" points="340,-390 196,-390 196,-174 340,-174 340,-390"></polygon>
<text text-anchor="middle" x="268" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealTimeProcessor</text>
</g>
<!-- RealearnAudioHook&#45;&gt;RealTimeProcessor -->
<g id="edge18" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M268,-123.23C268,-133.69 268,-148.05 268,-163.88"></path>
<polygon fill="black" stroke="black" points="264.5,-163.91 268,-173.91 271.5,-163.91 264.5,-163.91"></polygon>
<text text-anchor="middle" x="363" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- OscOutputDevice -->
<g id="node10" class="node layer-processing">
<title>OscOutputDevice</title>
<polygon fill="none" stroke="black" points="769.5,-123 654.5,-123 654.5,-87 769.5,-87 769.5,-123"></polygon>
<text text-anchor="middle" x="712" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OscOutputDevice</text>
</g>
<!-- infrastructure_layer -->
<!-- application_layer -->
<!-- infrastructure_layer&#45;&gt;application_layer -->
<!-- processing_layer -->
<!-- application_layer&#45;&gt;processing_layer -->
<!-- RealearnPlugin&#45;&gt;RealTimeProcessor -->
<g id="edge14" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>RealearnPlugin-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M267.41,-452.8C248.41,-448.11 228.62,-439.33 217,-423 211.94,-415.89 209.1,-408.22 207.98,-400.26"></path>
<polygon fill="black" stroke="black" points="211.46,-399.85 207.45,-390.05 204.47,-400.21 211.46,-399.85"></polygon>
<text text-anchor="middle" x="303.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- RealearnUi -->
<g id="node15" class="node layer-infrastructure">
<title>RealearnUi</title>
<polygon fill="none" stroke="black" points="489,-564 411,-564 411,-528 489,-528 489,-564"></polygon>
<text text-anchor="middle" x="450" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnUi</text>
</g>
<!-- Session -->
<g id="node16" class="node layer-management">
<title>Session</title>
<polygon fill="none" stroke="black" points="479,-477 421,-477 421,-441 479,-441 479,-477"></polygon>
<text text-anchor="middle" x="450" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Session</text>
</g>
<!-- Session&#45;&gt;RealearnUi -->
<g id="edge6" class="edge com-sync role-notify">
<title>Session-&gt;RealearnUi</title>
<path fill="none" stroke="black" d="M450,-477.18C450,-488.81 450,-504.42 450,-517.73"></path>
<polygon fill="black" stroke="black" points="446.5,-517.8 450,-527.8 453.5,-517.8 446.5,-517.8"></polygon>
<text text-anchor="middle" x="468.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- Session&#45;&gt;MainProcessor -->
<g id="edge3" class="edge com-async role-sync-data">
<title>Session-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M425.12,-440.9C414.75,-431.55 406.46,-419.56 413,-408 440.07,-360.14 493.6,-328.59 539.57,-309.16"></path>
<polygon fill="black" stroke="black" points="541.03,-312.35 548.96,-305.32 538.38,-305.87 541.03,-312.35"></polygon>
<text text-anchor="middle" x="440" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- InstanceState -->
<g id="node17" class="node layer-processing">
<title>InstanceState</title>
<polygon fill="none" stroke="black" points="800.5,-300 711.5,-300 711.5,-264 800.5,-264 800.5,-300"></polygon>
<text text-anchor="middle" x="756" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">InstanceState</text>
</g>
<!-- InstanceState&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge8" class="edge com-async dir-feedback type-general role-realtime-general">
<title>InstanceState-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M775.77,-300.29C801.97,-323.6 849.05,-366.94 885,-408 891.69,-415.64 898.45,-424.41 904.34,-432.45"></path>
<polygon fill="black" stroke="black" points="901.65,-434.72 910.33,-440.8 907.34,-430.63 901.65,-434.72"></polygon>
<text text-anchor="middle" x="958.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance change events</text>
</g>
<!-- RealTimeProcessor&#45;&gt;FxChain -->
<g id="edge16" class="edge com-sync dir-feedback type-midi-fx role-realtime-midi-fx">
<title>RealTimeProcessor-&gt;FxChain</title>
<path fill="none" stroke="black" d="M340.09,-319.15C393.75,-344.1 469.58,-375.33 540,-390 567.27,-395.68 1021.36,-388.25 1041,-408 1062.63,-429.75 1049.69,-447.31 1042,-477 1039.7,-485.86 1034.3,-486.14 1032,-495 1030.33,-501.45 1028.89,-504.1 1032,-510 1034.6,-514.93 1038.23,-519.3 1042.38,-523.13"></path>
<polygon fill="black" stroke="black" points="1040.3,-525.95 1050.3,-529.46 1044.67,-520.48 1040.3,-525.95"></polygon>
<text text-anchor="middle" x="1147.5" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
<!-- RealTimeProcessor&#45;&gt;MainProcessor -->
<g id="edge12" class="edge com-async dir-control type-midi-general role-realtime-midi-general">
<title>RealTimeProcessor-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M340.29,-282C397.87,-282 478.51,-282 538.6,-282"></path>
<polygon fill="black" stroke="black" points="538.81,-285.5 548.81,-282 538.81,-278.5 538.81,-285.5"></polygon>
<text text-anchor="middle" x="444.5" y="-288.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Control values (from MIDI events)</text>
</g>
<!-- MainProcessor&#45;&gt;RealearnAudioHook -->
<g id="edge19" class="edge com-async dir-feedback type-midi-device role-realtime-midi-device">
<title>MainProcessor-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M549,-218.05C507.06,-181.5 461.84,-142.36 459,-141 422.88,-123.69 379.14,-114.9 342.63,-110.46"></path>
<polygon fill="black" stroke="black" points="342.87,-106.97 332.54,-109.32 342.08,-113.92 342.87,-106.97"></polygon>
<text text-anchor="middle" x="578" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- MainProcessor&#45;&gt;OscOutputDevice -->
<g id="edge11" class="edge com-async dir-feedback type-osc role-realtime-osc">
<title>MainProcessor-&gt;OscOutputDevice</title>
<path fill="none" stroke="black" d="M680.91,-173.94C684.04,-167.9 687.09,-161.89 690,-156 693.73,-148.47 697.51,-140.16 700.86,-132.52"></path>
<polygon fill="black" stroke="black" points="704.09,-133.87 704.84,-123.3 697.66,-131.09 704.09,-133.87"></polygon>
<text text-anchor="middle" x="756.5" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC feedback events</text>
</g>
<!-- MainProcessor&#45;&gt;Session -->
<g id="edge5" class="edge com-sync role-notify">
<title>MainProcessor-&gt;Session</title>
<path fill="none" stroke="black" d="M548.86,-347.61C528.87,-366.49 507.57,-387.56 489,-408 481.97,-415.74 474.78,-424.62 468.53,-432.73"></path>
<polygon fill="black" stroke="black" points="465.65,-430.74 462.39,-440.82 471.22,-434.97 465.65,-430.74"></polygon>
<text text-anchor="middle" x="507.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge4" class="edge com-async role-sync-data">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.72,-298.95C545.95,-299.35 543.2,-299.7 540.5,-300 500.74,-304.39 404.05,-304.67 350.41,-299.96"></path>
<polygon fill="black" stroke="black" points="350.58,-296.46 340.28,-298.95 349.89,-303.42 350.58,-296.46"></polygon>
<text text-anchor="middle" x="444.5" y="-309.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge15" class="edge com-async dir-feedback type-midi-fx role-realtime-midi-fx">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.71,-265.11C545.77,-264.69 542.86,-264.31 540,-264 500.45,-259.66 404.27,-259.39 350.46,-264.1"></path>
<polygon fill="black" stroke="black" points="349.9,-260.64 340.29,-265.11 350.59,-267.61 349.9,-260.64"></polygon>
<text text-anchor="middle" x="444.5" y="-267.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style><style>.edge{visibility:hidden;}</style><style>.edge.role-realtime-general{visibility:visible;}</style><style>.edge.role-realtime-midi-general{visibility:visible;}</style><style>.edge.role-realtime-midi-device{visibility:visible;}</style></svg>

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,695 @@
<svg width="1251pt" height="642pt" viewBox="0.00 0.00 1251.00 642.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 638)">
<title>components</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-638 1247,-638 1247,4 -4,4"></polygon>
<g id="clust1" class="cluster level-1">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="158,-79 158,-626 1040,-626 1040,-79 158,-79"></polygon>
<text text-anchor="middle" x="599" y="-610.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<g id="clust2" class="cluster level-2">
<title>cluster_instance</title>
<polygon fill="none" stroke="black" points="166,-166 166,-595 808,-595 808,-166 166,-166"></polygon>
<text text-anchor="middle" x="487" y="-579.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance</text>
</g>
<!-- MidiInputDevice -->
<g id="node1" class="node">
<title>MidiInputDevice</title>
<polygon fill="none" stroke="black" points="110,-300 0,-300 0,-264 110,-264 110,-300"></polygon>
<text text-anchor="middle" x="55" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiInputDevice</text>
</g>
<!-- RealearnAudioHook -->
<g id="node9" class="node layer-processing">
<title>RealearnAudioHook</title>
<polygon fill="none" stroke="black" points="332.5,-123 203.5,-123 203.5,-87 332.5,-87 332.5,-123"></polygon>
<text text-anchor="middle" x="268" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnAudioHook</text>
</g>
<!-- MidiInputDevice&#45;&gt;RealearnAudioHook -->
<g id="edge17" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>MidiInputDevice-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M51.56,-263.66C46.81,-234.2 42.11,-174.31 74,-141 90.41,-123.86 145.94,-115.02 193.41,-110.52"></path>
<polygon fill="black" stroke="black" points="193.75,-114 203.4,-109.62 193.13,-107.03 193.75,-114"></polygon>
<text text-anchor="middle" x="169" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- MidiOutputDevice -->
<g id="node2" class="node">
<title>MidiOutputDevice</title>
<polygon fill="none" stroke="black" points="327.5,-36 208.5,-36 208.5,0 327.5,0 327.5,-36"></polygon>
<text text-anchor="middle" x="268" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiOutputDevice</text>
</g>
<!-- FxChain -->
<g id="node3" class="node">
<title>FxChain</title>
<polygon fill="none" stroke="black" points="1115.5,-564 1050.5,-564 1050.5,-528 1115.5,-528 1115.5,-564"></polygon>
<text text-anchor="middle" x="1083" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">FxChain</text>
</g>
<!-- RealearnPlugin -->
<g id="node14" class="node layer-infrastructure">
<title>RealearnPlugin</title>
<polygon fill="none" stroke="black" points="368.5,-477 267.5,-477 267.5,-441 368.5,-441 368.5,-477"></polygon>
<text text-anchor="middle" x="318" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnPlugin</text>
</g>
<!-- FxChain&#45;&gt;RealearnPlugin -->
<g id="edge13" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>FxChain-&gt;RealearnPlugin</title>
<path fill="none" stroke="black" d="M1050.07,-529.76C1048.04,-529.1 1046.01,-528.5 1044,-528 944.52,-503.17 916.21,-518.19 814,-510 635.31,-495.67 589.75,-500.31 412,-477 401.17,-475.58 389.7,-473.77 378.62,-471.85"></path>
<polygon fill="black" stroke="black" points="379.05,-468.38 368.59,-470.08 377.83,-475.27 379.05,-468.38"></polygon>
<text text-anchor="middle" x="900.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- Reaper -->
<g id="node4" class="node">
<title>Reaper</title>
<polygon fill="none" stroke="black" points="1188.5,-564 1133.5,-564 1133.5,-528 1188.5,-528 1188.5,-564"></polygon>
<text text-anchor="middle" x="1161" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Reaper</text>
</g>
<!-- RealearnControlSurfaceMiddleware -->
<g id="node8" class="node layer-processing">
<title>RealearnControlSurfaceMiddleware</title>
<polygon fill="none" stroke="black" points="1028,-477 816,-477 816,-441 1028,-441 1028,-477"></polygon>
<text text-anchor="middle" x="922" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnControlSurfaceMiddleware</text>
</g>
<!-- Reaper&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge7" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>Reaper-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M1133.24,-531.49C1130.47,-530.27 1127.69,-529.08 1125,-528 1080.08,-509.94 1028.31,-492.66 988.3,-480.03"></path>
<polygon fill="black" stroke="black" points="989.24,-476.66 978.65,-477.01 987.15,-483.34 989.24,-476.66"></polygon>
<text text-anchor="middle" x="1141.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER change events</text>
</g>
<!-- App -->
<g id="node5" class="node layer-infrastructure">
<title>App</title>
<polygon fill="none" stroke="black" points="1032,-564 978,-564 978,-528 1032,-528 1032,-564"></polygon>
<text text-anchor="middle" x="1005" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">App</text>
</g>
<!-- Server -->
<g id="node6" class="node layer-infrastructure">
<title>Server</title>
<polygon fill="none" stroke="black" points="960,-564 906,-564 906,-528 960,-528 960,-564"></polygon>
<text text-anchor="middle" x="933" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Server</text>
</g>
<!-- Backbone -->
<g id="node7" class="node layer-processing">
<title>Backbone</title>
<polygon fill="none" stroke="black" points="887.5,-564 816.5,-564 816.5,-528 887.5,-528 887.5,-564"></polygon>
<text text-anchor="middle" x="852" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Backbone</text>
</g>
<!-- MainProcessor -->
<g id="node19" class="node layer-processing">
<title>MainProcessor</title>
<polygon fill="none" stroke="black" points="693,-390 549,-390 549,-174 693,-174 693,-390"></polygon>
<text text-anchor="middle" x="621" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MainProcessor</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge9" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M815.77,-441.43C814.5,-441.28 813.25,-441.14 812,-441 783,-437.77 569.91,-444.33 550,-423 535.7,-407.68 536.4,-388.93 544.37,-370.19"></path>
<polygon fill="black" stroke="black" points="547.61,-371.53 548.84,-361.01 541.32,-368.47 547.61,-371.53"></polygon>
<text text-anchor="middle" x="652" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER and instance change events</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge10" class="edge com-sync dir-control type-osc role-realtime-osc">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M822.13,-440.94C805.29,-436.27 788.32,-430.39 773,-423 763.31,-418.33 763.42,-413.19 754,-408 732.95,-396.4 722.45,-404.12 703,-390 702.36,-389.54 701.72,-389.07 701.09,-388.59"></path>
<polygon fill="black" stroke="black" points="702.98,-385.62 693,-382.07 698.59,-391.07 702.98,-385.62"></polygon>
<text text-anchor="middle" x="827" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC control events</text>
</g>
<!-- RealearnAudioHook&#45;&gt;MidiOutputDevice -->
<g id="edge20" class="edge com-sync dir-feedback type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;MidiOutputDevice</title>
<path fill="none" stroke="black" d="M268,-86.8C268,-75.16 268,-59.55 268,-46.24"></path>
<polygon fill="black" stroke="black" points="271.5,-46.18 268,-36.18 264.5,-46.18 271.5,-46.18"></polygon>
<text text-anchor="middle" x="372" y="-57.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- RealTimeProcessor -->
<g id="node18" class="node layer-processing">
<title>RealTimeProcessor</title>
<polygon fill="none" stroke="black" points="340,-390 196,-390 196,-174 340,-174 340,-390"></polygon>
<text text-anchor="middle" x="268" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealTimeProcessor</text>
</g>
<!-- RealearnAudioHook&#45;&gt;RealTimeProcessor -->
<g id="edge18" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M268,-123.23C268,-133.69 268,-148.05 268,-163.88"></path>
<polygon fill="black" stroke="black" points="264.5,-163.91 268,-173.91 271.5,-163.91 264.5,-163.91"></polygon>
<text text-anchor="middle" x="363" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- OscOutputDevice -->
<g id="node10" class="node layer-processing">
<title>OscOutputDevice</title>
<polygon fill="none" stroke="black" points="769.5,-123 654.5,-123 654.5,-87 769.5,-87 769.5,-123"></polygon>
<text text-anchor="middle" x="712" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OscOutputDevice</text>
</g>
<!-- infrastructure_layer -->
<!-- application_layer -->
<!-- infrastructure_layer&#45;&gt;application_layer -->
<!-- processing_layer -->
<!-- application_layer&#45;&gt;processing_layer -->
<!-- RealearnPlugin&#45;&gt;RealTimeProcessor -->
<g id="edge14" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>RealearnPlugin-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M267.41,-452.8C248.41,-448.11 228.62,-439.33 217,-423 211.94,-415.89 209.1,-408.22 207.98,-400.26"></path>
<polygon fill="black" stroke="black" points="211.46,-399.85 207.45,-390.05 204.47,-400.21 211.46,-399.85"></polygon>
<text text-anchor="middle" x="303.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- RealearnUi -->
<g id="node15" class="node layer-infrastructure">
<title>RealearnUi</title>
<polygon fill="none" stroke="black" points="489,-564 411,-564 411,-528 489,-528 489,-564"></polygon>
<text text-anchor="middle" x="450" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnUi</text>
</g>
<!-- Session -->
<g id="node16" class="node layer-management">
<title>Session</title>
<polygon fill="none" stroke="black" points="479,-477 421,-477 421,-441 479,-441 479,-477"></polygon>
<text text-anchor="middle" x="450" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Session</text>
</g>
<!-- Session&#45;&gt;RealearnUi -->
<g id="edge6" class="edge com-sync role-notify">
<title>Session-&gt;RealearnUi</title>
<path fill="none" stroke="black" d="M450,-477.18C450,-488.81 450,-504.42 450,-517.73"></path>
<polygon fill="black" stroke="black" points="446.5,-517.8 450,-527.8 453.5,-517.8 446.5,-517.8"></polygon>
<text text-anchor="middle" x="468.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- Session&#45;&gt;MainProcessor -->
<g id="edge3" class="edge com-async role-sync-data">
<title>Session-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M425.12,-440.9C414.75,-431.55 406.46,-419.56 413,-408 440.07,-360.14 493.6,-328.59 539.57,-309.16"></path>
<polygon fill="black" stroke="black" points="541.03,-312.35 548.96,-305.32 538.38,-305.87 541.03,-312.35"></polygon>
<text text-anchor="middle" x="440" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- InstanceState -->
<g id="node17" class="node layer-processing">
<title>InstanceState</title>
<polygon fill="none" stroke="black" points="800.5,-300 711.5,-300 711.5,-264 800.5,-264 800.5,-300"></polygon>
<text text-anchor="middle" x="756" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">InstanceState</text>
</g>
<!-- InstanceState&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge8" class="edge com-async dir-feedback type-general role-realtime-general">
<title>InstanceState-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M775.77,-300.29C801.97,-323.6 849.05,-366.94 885,-408 891.69,-415.64 898.45,-424.41 904.34,-432.45"></path>
<polygon fill="black" stroke="black" points="901.65,-434.72 910.33,-440.8 907.34,-430.63 901.65,-434.72"></polygon>
<text text-anchor="middle" x="958.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance change events</text>
</g>
<!-- RealTimeProcessor&#45;&gt;FxChain -->
<g id="edge16" class="edge com-sync dir-feedback type-midi-fx role-realtime-midi-fx">
<title>RealTimeProcessor-&gt;FxChain</title>
<path fill="none" stroke="black" d="M340.09,-319.15C393.75,-344.1 469.58,-375.33 540,-390 567.27,-395.68 1021.36,-388.25 1041,-408 1062.63,-429.75 1049.69,-447.31 1042,-477 1039.7,-485.86 1034.3,-486.14 1032,-495 1030.33,-501.45 1028.89,-504.1 1032,-510 1034.6,-514.93 1038.23,-519.3 1042.38,-523.13"></path>
<polygon fill="black" stroke="black" points="1040.3,-525.95 1050.3,-529.46 1044.67,-520.48 1040.3,-525.95"></polygon>
<text text-anchor="middle" x="1147.5" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
<!-- RealTimeProcessor&#45;&gt;MainProcessor -->
<g id="edge12" class="edge com-async dir-control type-midi-general role-realtime-midi-general">
<title>RealTimeProcessor-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M340.29,-282C397.87,-282 478.51,-282 538.6,-282"></path>
<polygon fill="black" stroke="black" points="538.81,-285.5 548.81,-282 538.81,-278.5 538.81,-285.5"></polygon>
<text text-anchor="middle" x="444.5" y="-288.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Control values (from MIDI events)</text>
</g>
<!-- MainProcessor&#45;&gt;RealearnAudioHook -->
<g id="edge19" class="edge com-async dir-feedback type-midi-device role-realtime-midi-device">
<title>MainProcessor-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M549,-218.05C507.06,-181.5 461.84,-142.36 459,-141 422.88,-123.69 379.14,-114.9 342.63,-110.46"></path>
<polygon fill="black" stroke="black" points="342.87,-106.97 332.54,-109.32 342.08,-113.92 342.87,-106.97"></polygon>
<text text-anchor="middle" x="578" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- MainProcessor&#45;&gt;OscOutputDevice -->
<g id="edge11" class="edge com-async dir-feedback type-osc role-realtime-osc">
<title>MainProcessor-&gt;OscOutputDevice</title>
<path fill="none" stroke="black" d="M680.91,-173.94C684.04,-167.9 687.09,-161.89 690,-156 693.73,-148.47 697.51,-140.16 700.86,-132.52"></path>
<polygon fill="black" stroke="black" points="704.09,-133.87 704.84,-123.3 697.66,-131.09 704.09,-133.87"></polygon>
<text text-anchor="middle" x="756.5" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC feedback events</text>
</g>
<!-- MainProcessor&#45;&gt;Session -->
<g id="edge5" class="edge com-sync role-notify">
<title>MainProcessor-&gt;Session</title>
<path fill="none" stroke="black" d="M548.86,-347.61C528.87,-366.49 507.57,-387.56 489,-408 481.97,-415.74 474.78,-424.62 468.53,-432.73"></path>
<polygon fill="black" stroke="black" points="465.65,-430.74 462.39,-440.82 471.22,-434.97 465.65,-430.74"></polygon>
<text text-anchor="middle" x="507.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge4" class="edge com-async role-sync-data">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.72,-298.95C545.95,-299.35 543.2,-299.7 540.5,-300 500.74,-304.39 404.05,-304.67 350.41,-299.96"></path>
<polygon fill="black" stroke="black" points="350.58,-296.46 340.28,-298.95 349.89,-303.42 350.58,-296.46"></polygon>
<text text-anchor="middle" x="444.5" y="-309.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge15" class="edge com-async dir-feedback type-midi-fx role-realtime-midi-fx">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.71,-265.11C545.77,-264.69 542.86,-264.31 540,-264 500.45,-259.66 404.27,-259.39 350.46,-264.1"></path>
<polygon fill="black" stroke="black" points="349.9,-260.64 340.29,-265.11 350.59,-267.61 349.9,-260.64"></polygon>
<text text-anchor="middle" x="444.5" y="-267.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style><style>.edge{visibility:hidden;}</style><style>.edge.role-realtime-general{visibility:visible;}</style><style>.edge.role-realtime-midi-general{visibility:visible;}</style><style>.edge.role-realtime-midi-fx{visibility:visible;}</style></svg>

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,695 @@
<svg width="1251pt" height="642pt" viewBox="0.00 0.00 1251.00 642.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 638)">
<title>components</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-638 1247,-638 1247,4 -4,4"></polygon>
<g id="clust1" class="cluster level-1">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="158,-79 158,-626 1040,-626 1040,-79 158,-79"></polygon>
<text text-anchor="middle" x="599" y="-610.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<g id="clust2" class="cluster level-2">
<title>cluster_instance</title>
<polygon fill="none" stroke="black" points="166,-166 166,-595 808,-595 808,-166 166,-166"></polygon>
<text text-anchor="middle" x="487" y="-579.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance</text>
</g>
<!-- MidiInputDevice -->
<g id="node1" class="node">
<title>MidiInputDevice</title>
<polygon fill="none" stroke="black" points="110,-300 0,-300 0,-264 110,-264 110,-300"></polygon>
<text text-anchor="middle" x="55" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiInputDevice</text>
</g>
<!-- RealearnAudioHook -->
<g id="node9" class="node layer-processing">
<title>RealearnAudioHook</title>
<polygon fill="none" stroke="black" points="332.5,-123 203.5,-123 203.5,-87 332.5,-87 332.5,-123"></polygon>
<text text-anchor="middle" x="268" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnAudioHook</text>
</g>
<!-- MidiInputDevice&#45;&gt;RealearnAudioHook -->
<g id="edge17" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>MidiInputDevice-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M51.56,-263.66C46.81,-234.2 42.11,-174.31 74,-141 90.41,-123.86 145.94,-115.02 193.41,-110.52"></path>
<polygon fill="black" stroke="black" points="193.75,-114 203.4,-109.62 193.13,-107.03 193.75,-114"></polygon>
<text text-anchor="middle" x="169" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- MidiOutputDevice -->
<g id="node2" class="node">
<title>MidiOutputDevice</title>
<polygon fill="none" stroke="black" points="327.5,-36 208.5,-36 208.5,0 327.5,0 327.5,-36"></polygon>
<text text-anchor="middle" x="268" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiOutputDevice</text>
</g>
<!-- FxChain -->
<g id="node3" class="node">
<title>FxChain</title>
<polygon fill="none" stroke="black" points="1115.5,-564 1050.5,-564 1050.5,-528 1115.5,-528 1115.5,-564"></polygon>
<text text-anchor="middle" x="1083" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">FxChain</text>
</g>
<!-- RealearnPlugin -->
<g id="node14" class="node layer-infrastructure">
<title>RealearnPlugin</title>
<polygon fill="none" stroke="black" points="368.5,-477 267.5,-477 267.5,-441 368.5,-441 368.5,-477"></polygon>
<text text-anchor="middle" x="318" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnPlugin</text>
</g>
<!-- FxChain&#45;&gt;RealearnPlugin -->
<g id="edge13" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>FxChain-&gt;RealearnPlugin</title>
<path fill="none" stroke="black" d="M1050.07,-529.76C1048.04,-529.1 1046.01,-528.5 1044,-528 944.52,-503.17 916.21,-518.19 814,-510 635.31,-495.67 589.75,-500.31 412,-477 401.17,-475.58 389.7,-473.77 378.62,-471.85"></path>
<polygon fill="black" stroke="black" points="379.05,-468.38 368.59,-470.08 377.83,-475.27 379.05,-468.38"></polygon>
<text text-anchor="middle" x="900.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- Reaper -->
<g id="node4" class="node">
<title>Reaper</title>
<polygon fill="none" stroke="black" points="1188.5,-564 1133.5,-564 1133.5,-528 1188.5,-528 1188.5,-564"></polygon>
<text text-anchor="middle" x="1161" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Reaper</text>
</g>
<!-- RealearnControlSurfaceMiddleware -->
<g id="node8" class="node layer-processing">
<title>RealearnControlSurfaceMiddleware</title>
<polygon fill="none" stroke="black" points="1028,-477 816,-477 816,-441 1028,-441 1028,-477"></polygon>
<text text-anchor="middle" x="922" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnControlSurfaceMiddleware</text>
</g>
<!-- Reaper&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge7" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>Reaper-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M1133.24,-531.49C1130.47,-530.27 1127.69,-529.08 1125,-528 1080.08,-509.94 1028.31,-492.66 988.3,-480.03"></path>
<polygon fill="black" stroke="black" points="989.24,-476.66 978.65,-477.01 987.15,-483.34 989.24,-476.66"></polygon>
<text text-anchor="middle" x="1141.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER change events</text>
</g>
<!-- App -->
<g id="node5" class="node layer-infrastructure">
<title>App</title>
<polygon fill="none" stroke="black" points="1032,-564 978,-564 978,-528 1032,-528 1032,-564"></polygon>
<text text-anchor="middle" x="1005" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">App</text>
</g>
<!-- Server -->
<g id="node6" class="node layer-infrastructure">
<title>Server</title>
<polygon fill="none" stroke="black" points="960,-564 906,-564 906,-528 960,-528 960,-564"></polygon>
<text text-anchor="middle" x="933" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Server</text>
</g>
<!-- Backbone -->
<g id="node7" class="node layer-processing">
<title>Backbone</title>
<polygon fill="none" stroke="black" points="887.5,-564 816.5,-564 816.5,-528 887.5,-528 887.5,-564"></polygon>
<text text-anchor="middle" x="852" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Backbone</text>
</g>
<!-- MainProcessor -->
<g id="node19" class="node layer-processing">
<title>MainProcessor</title>
<polygon fill="none" stroke="black" points="693,-390 549,-390 549,-174 693,-174 693,-390"></polygon>
<text text-anchor="middle" x="621" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MainProcessor</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge9" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M815.77,-441.43C814.5,-441.28 813.25,-441.14 812,-441 783,-437.77 569.91,-444.33 550,-423 535.7,-407.68 536.4,-388.93 544.37,-370.19"></path>
<polygon fill="black" stroke="black" points="547.61,-371.53 548.84,-361.01 541.32,-368.47 547.61,-371.53"></polygon>
<text text-anchor="middle" x="652" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER and instance change events</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge10" class="edge com-sync dir-control type-osc role-realtime-osc">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M822.13,-440.94C805.29,-436.27 788.32,-430.39 773,-423 763.31,-418.33 763.42,-413.19 754,-408 732.95,-396.4 722.45,-404.12 703,-390 702.36,-389.54 701.72,-389.07 701.09,-388.59"></path>
<polygon fill="black" stroke="black" points="702.98,-385.62 693,-382.07 698.59,-391.07 702.98,-385.62"></polygon>
<text text-anchor="middle" x="827" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC control events</text>
</g>
<!-- RealearnAudioHook&#45;&gt;MidiOutputDevice -->
<g id="edge20" class="edge com-sync dir-feedback type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;MidiOutputDevice</title>
<path fill="none" stroke="black" d="M268,-86.8C268,-75.16 268,-59.55 268,-46.24"></path>
<polygon fill="black" stroke="black" points="271.5,-46.18 268,-36.18 264.5,-46.18 271.5,-46.18"></polygon>
<text text-anchor="middle" x="372" y="-57.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- RealTimeProcessor -->
<g id="node18" class="node layer-processing">
<title>RealTimeProcessor</title>
<polygon fill="none" stroke="black" points="340,-390 196,-390 196,-174 340,-174 340,-390"></polygon>
<text text-anchor="middle" x="268" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealTimeProcessor</text>
</g>
<!-- RealearnAudioHook&#45;&gt;RealTimeProcessor -->
<g id="edge18" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M268,-123.23C268,-133.69 268,-148.05 268,-163.88"></path>
<polygon fill="black" stroke="black" points="264.5,-163.91 268,-173.91 271.5,-163.91 264.5,-163.91"></polygon>
<text text-anchor="middle" x="363" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- OscOutputDevice -->
<g id="node10" class="node layer-processing">
<title>OscOutputDevice</title>
<polygon fill="none" stroke="black" points="769.5,-123 654.5,-123 654.5,-87 769.5,-87 769.5,-123"></polygon>
<text text-anchor="middle" x="712" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OscOutputDevice</text>
</g>
<!-- infrastructure_layer -->
<!-- application_layer -->
<!-- infrastructure_layer&#45;&gt;application_layer -->
<!-- processing_layer -->
<!-- application_layer&#45;&gt;processing_layer -->
<!-- RealearnPlugin&#45;&gt;RealTimeProcessor -->
<g id="edge14" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>RealearnPlugin-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M267.41,-452.8C248.41,-448.11 228.62,-439.33 217,-423 211.94,-415.89 209.1,-408.22 207.98,-400.26"></path>
<polygon fill="black" stroke="black" points="211.46,-399.85 207.45,-390.05 204.47,-400.21 211.46,-399.85"></polygon>
<text text-anchor="middle" x="303.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- RealearnUi -->
<g id="node15" class="node layer-infrastructure">
<title>RealearnUi</title>
<polygon fill="none" stroke="black" points="489,-564 411,-564 411,-528 489,-528 489,-564"></polygon>
<text text-anchor="middle" x="450" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnUi</text>
</g>
<!-- Session -->
<g id="node16" class="node layer-management">
<title>Session</title>
<polygon fill="none" stroke="black" points="479,-477 421,-477 421,-441 479,-441 479,-477"></polygon>
<text text-anchor="middle" x="450" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Session</text>
</g>
<!-- Session&#45;&gt;RealearnUi -->
<g id="edge6" class="edge com-sync role-notify">
<title>Session-&gt;RealearnUi</title>
<path fill="none" stroke="black" d="M450,-477.18C450,-488.81 450,-504.42 450,-517.73"></path>
<polygon fill="black" stroke="black" points="446.5,-517.8 450,-527.8 453.5,-517.8 446.5,-517.8"></polygon>
<text text-anchor="middle" x="468.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- Session&#45;&gt;MainProcessor -->
<g id="edge3" class="edge com-async role-sync-data">
<title>Session-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M425.12,-440.9C414.75,-431.55 406.46,-419.56 413,-408 440.07,-360.14 493.6,-328.59 539.57,-309.16"></path>
<polygon fill="black" stroke="black" points="541.03,-312.35 548.96,-305.32 538.38,-305.87 541.03,-312.35"></polygon>
<text text-anchor="middle" x="440" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- InstanceState -->
<g id="node17" class="node layer-processing">
<title>InstanceState</title>
<polygon fill="none" stroke="black" points="800.5,-300 711.5,-300 711.5,-264 800.5,-264 800.5,-300"></polygon>
<text text-anchor="middle" x="756" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">InstanceState</text>
</g>
<!-- InstanceState&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge8" class="edge com-async dir-feedback type-general role-realtime-general">
<title>InstanceState-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M775.77,-300.29C801.97,-323.6 849.05,-366.94 885,-408 891.69,-415.64 898.45,-424.41 904.34,-432.45"></path>
<polygon fill="black" stroke="black" points="901.65,-434.72 910.33,-440.8 907.34,-430.63 901.65,-434.72"></polygon>
<text text-anchor="middle" x="958.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance change events</text>
</g>
<!-- RealTimeProcessor&#45;&gt;FxChain -->
<g id="edge16" class="edge com-sync dir-feedback type-midi-fx role-realtime-midi-fx">
<title>RealTimeProcessor-&gt;FxChain</title>
<path fill="none" stroke="black" d="M340.09,-319.15C393.75,-344.1 469.58,-375.33 540,-390 567.27,-395.68 1021.36,-388.25 1041,-408 1062.63,-429.75 1049.69,-447.31 1042,-477 1039.7,-485.86 1034.3,-486.14 1032,-495 1030.33,-501.45 1028.89,-504.1 1032,-510 1034.6,-514.93 1038.23,-519.3 1042.38,-523.13"></path>
<polygon fill="black" stroke="black" points="1040.3,-525.95 1050.3,-529.46 1044.67,-520.48 1040.3,-525.95"></polygon>
<text text-anchor="middle" x="1147.5" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
<!-- RealTimeProcessor&#45;&gt;MainProcessor -->
<g id="edge12" class="edge com-async dir-control type-midi-general role-realtime-midi-general">
<title>RealTimeProcessor-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M340.29,-282C397.87,-282 478.51,-282 538.6,-282"></path>
<polygon fill="black" stroke="black" points="538.81,-285.5 548.81,-282 538.81,-278.5 538.81,-285.5"></polygon>
<text text-anchor="middle" x="444.5" y="-288.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Control values (from MIDI events)</text>
</g>
<!-- MainProcessor&#45;&gt;RealearnAudioHook -->
<g id="edge19" class="edge com-async dir-feedback type-midi-device role-realtime-midi-device">
<title>MainProcessor-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M549,-218.05C507.06,-181.5 461.84,-142.36 459,-141 422.88,-123.69 379.14,-114.9 342.63,-110.46"></path>
<polygon fill="black" stroke="black" points="342.87,-106.97 332.54,-109.32 342.08,-113.92 342.87,-106.97"></polygon>
<text text-anchor="middle" x="578" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- MainProcessor&#45;&gt;OscOutputDevice -->
<g id="edge11" class="edge com-async dir-feedback type-osc role-realtime-osc">
<title>MainProcessor-&gt;OscOutputDevice</title>
<path fill="none" stroke="black" d="M680.91,-173.94C684.04,-167.9 687.09,-161.89 690,-156 693.73,-148.47 697.51,-140.16 700.86,-132.52"></path>
<polygon fill="black" stroke="black" points="704.09,-133.87 704.84,-123.3 697.66,-131.09 704.09,-133.87"></polygon>
<text text-anchor="middle" x="756.5" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC feedback events</text>
</g>
<!-- MainProcessor&#45;&gt;Session -->
<g id="edge5" class="edge com-sync role-notify">
<title>MainProcessor-&gt;Session</title>
<path fill="none" stroke="black" d="M548.86,-347.61C528.87,-366.49 507.57,-387.56 489,-408 481.97,-415.74 474.78,-424.62 468.53,-432.73"></path>
<polygon fill="black" stroke="black" points="465.65,-430.74 462.39,-440.82 471.22,-434.97 465.65,-430.74"></polygon>
<text text-anchor="middle" x="507.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge4" class="edge com-async role-sync-data">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.72,-298.95C545.95,-299.35 543.2,-299.7 540.5,-300 500.74,-304.39 404.05,-304.67 350.41,-299.96"></path>
<polygon fill="black" stroke="black" points="350.58,-296.46 340.28,-298.95 349.89,-303.42 350.58,-296.46"></polygon>
<text text-anchor="middle" x="444.5" y="-309.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge15" class="edge com-async dir-feedback type-midi-fx role-realtime-midi-fx">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.71,-265.11C545.77,-264.69 542.86,-264.31 540,-264 500.45,-259.66 404.27,-259.39 350.46,-264.1"></path>
<polygon fill="black" stroke="black" points="349.9,-260.64 340.29,-265.11 350.59,-267.61 349.9,-260.64"></polygon>
<text text-anchor="middle" x="444.5" y="-267.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style><style>.edge{visibility:hidden;}</style><style>.edge.role-realtime-general{visibility:visible;}</style><style>.edge.role-realtime-osc{visibility:visible;}</style></svg>

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,695 @@
<svg width="1251pt" height="642pt" viewBox="0.00 0.00 1251.00 642.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 638)">
<title>components</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-638 1247,-638 1247,4 -4,4"></polygon>
<g id="clust1" class="cluster level-1">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="158,-79 158,-626 1040,-626 1040,-79 158,-79"></polygon>
<text text-anchor="middle" x="599" y="-610.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<g id="clust2" class="cluster level-2">
<title>cluster_instance</title>
<polygon fill="none" stroke="black" points="166,-166 166,-595 808,-595 808,-166 166,-166"></polygon>
<text text-anchor="middle" x="487" y="-579.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance</text>
</g>
<!-- MidiInputDevice -->
<g id="node1" class="node">
<title>MidiInputDevice</title>
<polygon fill="none" stroke="black" points="110,-300 0,-300 0,-264 110,-264 110,-300"></polygon>
<text text-anchor="middle" x="55" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiInputDevice</text>
</g>
<!-- RealearnAudioHook -->
<g id="node9" class="node layer-processing">
<title>RealearnAudioHook</title>
<polygon fill="none" stroke="black" points="332.5,-123 203.5,-123 203.5,-87 332.5,-87 332.5,-123"></polygon>
<text text-anchor="middle" x="268" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnAudioHook</text>
</g>
<!-- MidiInputDevice&#45;&gt;RealearnAudioHook -->
<g id="edge17" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>MidiInputDevice-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M51.56,-263.66C46.81,-234.2 42.11,-174.31 74,-141 90.41,-123.86 145.94,-115.02 193.41,-110.52"></path>
<polygon fill="black" stroke="black" points="193.75,-114 203.4,-109.62 193.13,-107.03 193.75,-114"></polygon>
<text text-anchor="middle" x="169" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- MidiOutputDevice -->
<g id="node2" class="node">
<title>MidiOutputDevice</title>
<polygon fill="none" stroke="black" points="327.5,-36 208.5,-36 208.5,0 327.5,0 327.5,-36"></polygon>
<text text-anchor="middle" x="268" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MidiOutputDevice</text>
</g>
<!-- FxChain -->
<g id="node3" class="node">
<title>FxChain</title>
<polygon fill="none" stroke="black" points="1115.5,-564 1050.5,-564 1050.5,-528 1115.5,-528 1115.5,-564"></polygon>
<text text-anchor="middle" x="1083" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">FxChain</text>
</g>
<!-- RealearnPlugin -->
<g id="node14" class="node layer-infrastructure">
<title>RealearnPlugin</title>
<polygon fill="none" stroke="black" points="368.5,-477 267.5,-477 267.5,-441 368.5,-441 368.5,-477"></polygon>
<text text-anchor="middle" x="318" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnPlugin</text>
</g>
<!-- FxChain&#45;&gt;RealearnPlugin -->
<g id="edge13" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>FxChain-&gt;RealearnPlugin</title>
<path fill="none" stroke="black" d="M1050.07,-529.76C1048.04,-529.1 1046.01,-528.5 1044,-528 944.52,-503.17 916.21,-518.19 814,-510 635.31,-495.67 589.75,-500.31 412,-477 401.17,-475.58 389.7,-473.77 378.62,-471.85"></path>
<polygon fill="black" stroke="black" points="379.05,-468.38 368.59,-470.08 377.83,-475.27 379.05,-468.38"></polygon>
<text text-anchor="middle" x="900.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- Reaper -->
<g id="node4" class="node">
<title>Reaper</title>
<polygon fill="none" stroke="black" points="1188.5,-564 1133.5,-564 1133.5,-528 1188.5,-528 1188.5,-564"></polygon>
<text text-anchor="middle" x="1161" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Reaper</text>
</g>
<!-- RealearnControlSurfaceMiddleware -->
<g id="node8" class="node layer-processing">
<title>RealearnControlSurfaceMiddleware</title>
<polygon fill="none" stroke="black" points="1028,-477 816,-477 816,-441 1028,-441 1028,-477"></polygon>
<text text-anchor="middle" x="922" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnControlSurfaceMiddleware</text>
</g>
<!-- Reaper&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge7" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>Reaper-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M1133.24,-531.49C1130.47,-530.27 1127.69,-529.08 1125,-528 1080.08,-509.94 1028.31,-492.66 988.3,-480.03"></path>
<polygon fill="black" stroke="black" points="989.24,-476.66 978.65,-477.01 987.15,-483.34 989.24,-476.66"></polygon>
<text text-anchor="middle" x="1141.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER change events</text>
</g>
<!-- App -->
<g id="node5" class="node layer-infrastructure">
<title>App</title>
<polygon fill="none" stroke="black" points="1032,-564 978,-564 978,-528 1032,-528 1032,-564"></polygon>
<text text-anchor="middle" x="1005" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">App</text>
</g>
<!-- Server -->
<g id="node6" class="node layer-infrastructure">
<title>Server</title>
<polygon fill="none" stroke="black" points="960,-564 906,-564 906,-528 960,-528 960,-564"></polygon>
<text text-anchor="middle" x="933" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Server</text>
</g>
<!-- Backbone -->
<g id="node7" class="node layer-processing">
<title>Backbone</title>
<polygon fill="none" stroke="black" points="887.5,-564 816.5,-564 816.5,-528 887.5,-528 887.5,-564"></polygon>
<text text-anchor="middle" x="852" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Backbone</text>
</g>
<!-- MainProcessor -->
<g id="node19" class="node layer-processing">
<title>MainProcessor</title>
<polygon fill="none" stroke="black" points="693,-390 549,-390 549,-174 693,-174 693,-390"></polygon>
<text text-anchor="middle" x="621" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MainProcessor</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge9" class="edge com-sync dir-feedback type-general role-realtime-general">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M815.77,-441.43C814.5,-441.28 813.25,-441.14 812,-441 783,-437.77 569.91,-444.33 550,-423 535.7,-407.68 536.4,-388.93 544.37,-370.19"></path>
<polygon fill="black" stroke="black" points="547.61,-371.53 548.84,-361.01 541.32,-368.47 547.61,-371.53"></polygon>
<text text-anchor="middle" x="652" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">REAPER and instance change events</text>
</g>
<!-- RealearnControlSurfaceMiddleware&#45;&gt;MainProcessor -->
<g id="edge10" class="edge com-sync dir-control type-osc role-realtime-osc">
<title>RealearnControlSurfaceMiddleware-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M822.13,-440.94C805.29,-436.27 788.32,-430.39 773,-423 763.31,-418.33 763.42,-413.19 754,-408 732.95,-396.4 722.45,-404.12 703,-390 702.36,-389.54 701.72,-389.07 701.09,-388.59"></path>
<polygon fill="black" stroke="black" points="702.98,-385.62 693,-382.07 698.59,-391.07 702.98,-385.62"></polygon>
<text text-anchor="middle" x="827" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC control events</text>
</g>
<!-- RealearnAudioHook&#45;&gt;MidiOutputDevice -->
<g id="edge20" class="edge com-sync dir-feedback type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;MidiOutputDevice</title>
<path fill="none" stroke="black" d="M268,-86.8C268,-75.16 268,-59.55 268,-46.24"></path>
<polygon fill="black" stroke="black" points="271.5,-46.18 268,-36.18 264.5,-46.18 271.5,-46.18"></polygon>
<text text-anchor="middle" x="372" y="-57.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- RealTimeProcessor -->
<g id="node18" class="node layer-processing">
<title>RealTimeProcessor</title>
<polygon fill="none" stroke="black" points="340,-390 196,-390 196,-174 340,-174 340,-390"></polygon>
<text text-anchor="middle" x="268" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealTimeProcessor</text>
</g>
<!-- RealearnAudioHook&#45;&gt;RealTimeProcessor -->
<g id="edge18" class="edge com-sync dir-control type-midi-device role-realtime-midi-device">
<title>RealearnAudioHook-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M268,-123.23C268,-133.69 268,-148.05 268,-163.88"></path>
<polygon fill="black" stroke="black" points="264.5,-163.91 268,-173.91 271.5,-163.91 264.5,-163.91"></polygon>
<text text-anchor="middle" x="363" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (device input)</text>
</g>
<!-- OscOutputDevice -->
<g id="node10" class="node layer-processing">
<title>OscOutputDevice</title>
<polygon fill="none" stroke="black" points="769.5,-123 654.5,-123 654.5,-87 769.5,-87 769.5,-123"></polygon>
<text text-anchor="middle" x="712" y="-101.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OscOutputDevice</text>
</g>
<!-- infrastructure_layer -->
<!-- application_layer -->
<!-- infrastructure_layer&#45;&gt;application_layer -->
<!-- processing_layer -->
<!-- application_layer&#45;&gt;processing_layer -->
<!-- RealearnPlugin&#45;&gt;RealTimeProcessor -->
<g id="edge14" class="edge com-sync dir-control type-midi-fx role-realtime-midi-fx">
<title>RealearnPlugin-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M267.41,-452.8C248.41,-448.11 228.62,-439.33 217,-423 211.94,-415.89 209.1,-408.22 207.98,-400.26"></path>
<polygon fill="black" stroke="black" points="211.46,-399.85 207.45,-390.05 204.47,-400.21 211.46,-399.85"></polygon>
<text text-anchor="middle" x="303.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI control events (FX input)</text>
</g>
<!-- RealearnUi -->
<g id="node15" class="node layer-infrastructure">
<title>RealearnUi</title>
<polygon fill="none" stroke="black" points="489,-564 411,-564 411,-528 489,-528 489,-564"></polygon>
<text text-anchor="middle" x="450" y="-542.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">RealearnUi</text>
</g>
<!-- Session -->
<g id="node16" class="node layer-management">
<title>Session</title>
<polygon fill="none" stroke="black" points="479,-477 421,-477 421,-441 479,-441 479,-477"></polygon>
<text text-anchor="middle" x="450" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Session</text>
</g>
<!-- Session&#45;&gt;RealearnUi -->
<g id="edge6" class="edge com-sync role-notify">
<title>Session-&gt;RealearnUi</title>
<path fill="none" stroke="black" d="M450,-477.18C450,-488.81 450,-504.42 450,-517.73"></path>
<polygon fill="black" stroke="black" points="446.5,-517.8 450,-527.8 453.5,-517.8 446.5,-517.8"></polygon>
<text text-anchor="middle" x="468.5" y="-498.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- Session&#45;&gt;MainProcessor -->
<g id="edge3" class="edge com-async role-sync-data">
<title>Session-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M425.12,-440.9C414.75,-431.55 406.46,-419.56 413,-408 440.07,-360.14 493.6,-328.59 539.57,-309.16"></path>
<polygon fill="black" stroke="black" points="541.03,-312.35 548.96,-305.32 538.38,-305.87 541.03,-312.35"></polygon>
<text text-anchor="middle" x="440" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- InstanceState -->
<g id="node17" class="node layer-processing">
<title>InstanceState</title>
<polygon fill="none" stroke="black" points="800.5,-300 711.5,-300 711.5,-264 800.5,-264 800.5,-300"></polygon>
<text text-anchor="middle" x="756" y="-278.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">InstanceState</text>
</g>
<!-- InstanceState&#45;&gt;RealearnControlSurfaceMiddleware -->
<g id="edge8" class="edge com-async dir-feedback type-general role-realtime-general">
<title>InstanceState-&gt;RealearnControlSurfaceMiddleware</title>
<path fill="none" stroke="black" d="M775.77,-300.29C801.97,-323.6 849.05,-366.94 885,-408 891.69,-415.64 898.45,-424.41 904.34,-432.45"></path>
<polygon fill="black" stroke="black" points="901.65,-434.72 910.33,-440.8 907.34,-430.63 901.65,-434.72"></polygon>
<text text-anchor="middle" x="958.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Instance change events</text>
</g>
<!-- RealTimeProcessor&#45;&gt;FxChain -->
<g id="edge16" class="edge com-sync dir-feedback type-midi-fx role-realtime-midi-fx">
<title>RealTimeProcessor-&gt;FxChain</title>
<path fill="none" stroke="black" d="M340.09,-319.15C393.75,-344.1 469.58,-375.33 540,-390 567.27,-395.68 1021.36,-388.25 1041,-408 1062.63,-429.75 1049.69,-447.31 1042,-477 1039.7,-485.86 1034.3,-486.14 1032,-495 1030.33,-501.45 1028.89,-504.1 1032,-510 1034.6,-514.93 1038.23,-519.3 1042.38,-523.13"></path>
<polygon fill="black" stroke="black" points="1040.3,-525.95 1050.3,-529.46 1044.67,-520.48 1040.3,-525.95"></polygon>
<text text-anchor="middle" x="1147.5" y="-455.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
<!-- RealTimeProcessor&#45;&gt;MainProcessor -->
<g id="edge12" class="edge com-async dir-control type-midi-general role-realtime-midi-general">
<title>RealTimeProcessor-&gt;MainProcessor</title>
<path fill="none" stroke="black" d="M340.29,-282C397.87,-282 478.51,-282 538.6,-282"></path>
<polygon fill="black" stroke="black" points="538.81,-285.5 548.81,-282 538.81,-278.5 538.81,-285.5"></polygon>
<text text-anchor="middle" x="444.5" y="-288.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Control values (from MIDI events)</text>
</g>
<!-- MainProcessor&#45;&gt;RealearnAudioHook -->
<g id="edge19" class="edge com-async dir-feedback type-midi-device role-realtime-midi-device">
<title>MainProcessor-&gt;RealearnAudioHook</title>
<path fill="none" stroke="black" d="M549,-218.05C507.06,-181.5 461.84,-142.36 459,-141 422.88,-123.69 379.14,-114.9 342.63,-110.46"></path>
<polygon fill="black" stroke="black" points="342.87,-106.97 332.54,-109.32 342.08,-113.92 342.87,-106.97"></polygon>
<text text-anchor="middle" x="578" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (device output)</text>
</g>
<!-- MainProcessor&#45;&gt;OscOutputDevice -->
<g id="edge11" class="edge com-async dir-feedback type-osc role-realtime-osc">
<title>MainProcessor-&gt;OscOutputDevice</title>
<path fill="none" stroke="black" d="M680.91,-173.94C684.04,-167.9 687.09,-161.89 690,-156 693.73,-148.47 697.51,-140.16 700.86,-132.52"></path>
<polygon fill="black" stroke="black" points="704.09,-133.87 704.84,-123.3 697.66,-131.09 704.09,-133.87"></polygon>
<text text-anchor="middle" x="756.5" y="-144.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">OSC feedback events</text>
</g>
<!-- MainProcessor&#45;&gt;Session -->
<g id="edge5" class="edge com-sync role-notify">
<title>MainProcessor-&gt;Session</title>
<path fill="none" stroke="black" d="M548.86,-347.61C528.87,-366.49 507.57,-387.56 489,-408 481.97,-415.74 474.78,-424.62 468.53,-432.73"></path>
<polygon fill="black" stroke="black" points="465.65,-430.74 462.39,-440.82 471.22,-434.97 465.65,-430.74"></polygon>
<text text-anchor="middle" x="507.5" y="-411.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Events</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge4" class="edge com-async role-sync-data">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.72,-298.95C545.95,-299.35 543.2,-299.7 540.5,-300 500.74,-304.39 404.05,-304.67 350.41,-299.96"></path>
<polygon fill="black" stroke="black" points="350.58,-296.46 340.28,-298.95 349.89,-303.42 350.58,-296.46"></polygon>
<text text-anchor="middle" x="444.5" y="-309.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">Sync data</text>
</g>
<!-- MainProcessor&#45;&gt;RealTimeProcessor -->
<g id="edge15" class="edge com-async dir-feedback type-midi-fx role-realtime-midi-fx">
<title>MainProcessor-&gt;RealTimeProcessor</title>
<path fill="none" stroke="black" d="M548.71,-265.11C545.77,-264.69 542.86,-264.31 540,-264 500.45,-259.66 404.27,-259.39 350.46,-264.1"></path>
<polygon fill="black" stroke="black" points="349.9,-260.64 340.29,-265.11 350.59,-267.61 349.9,-260.64"></polygon>
<text text-anchor="middle" x="444.5" y="-267.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">MIDI feedback events (FX output)</text>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style></svg>

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="C:\Users\benja\Documents\projects\dev\realearn-videos\realearn-logo.png"
id="SVGRoot"
version="1.1"
viewBox="0 0 3840 2160"
height="2160"
width="3840"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="logo.svg">
<defs
id="defs2015">
<rect
x="2862.8571"
y="891.42855"
width="862.85712"
height="925.71426"
id="rect2101" />
<filter
inkscape:label="Inset"
inkscape:menu="Shadows and Glows"
inkscape:menu-tooltip="Shadowy outer bevel"
style="color-interpolation-filters:sRGB;"
id="filter2177">
<feMorphology
result="result1"
in="SourceAlpha"
operator="dilate"
radius="3.6"
id="feMorphology2165" />
<feGaussianBlur
stdDeviation="3.6"
in="result1"
result="result0"
id="feGaussianBlur2167" />
<feDiffuseLighting
surfaceScale="-5"
id="feDiffuseLighting2171">
<feDistantLight
elevation="45"
azimuth="225"
id="feDistantLight2169" />
</feDiffuseLighting>
<feComposite
in2="result0"
operator="in"
result="result91"
id="feComposite2173" />
<feComposite
in="SourceGraphic"
in2="result91"
id="feComposite2175" />
</filter>
</defs>
<sodipodi:namedview
inkscape:snap-page="true"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.12374369"
inkscape:cx="-1069.519"
inkscape:cy="1695.1039"
inkscape:document-units="px"
inkscape:current-layer="layer2"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:window-x="-6"
inkscape:window-y="-6"
inkscape:window-maximized="1" />
<metadata
id="metadata2018">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Background"
id="layer2"
inkscape:groupmode="layer"
style="display:inline">
<rect
y="0"
x="0"
height="2160"
width="3840"
id="rect933"
style="fill:#252525;stroke-width:4.02492;stroke-linecap:round;stroke-linejoin:round" />
</g>
<g
style="display:inline"
inkscape:label="Icon"
inkscape:groupmode="layer"
id="layer1">
<g
transform="translate(0,-27.272865)"
id="g956" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="companion"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="ReaLearn"
style="display:inline">
<g
transform="matrix(2.4830732,0,0,2.4830732,144.87612,-1568.1107)"
id="g932"
style="display:inline">
<g
id="layer3-6"
inkscape:label="Square background (helper)"
style="display:none">
<rect
style="fill:#252525;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
id="rect3248"
width="512"
height="512"
x="0"
y="0" />
</g>
<g
inkscape:label="LEDs"
id="layer1-0"
style="display:inline">
<text
id="text1034"
y="-505.30029"
x="415.02316"
style="font-style:normal;font-weight:normal;font-size:39.9999px;line-height:1.25;font-family:sans-serif;display:inline;fill:#ffd5d5;fill-opacity:1;stroke:none;stroke-width:0.999999"
xml:space="preserve"><tspan
style="fill:#ffd5d5;stroke-width:0.999999"
y="-505.30029"
x="415.02316"
id="tspan1032"
sodipodi:role="line" /></text>
</g>
<g
id="layer2-6"
inkscape:label="LED alignment circle (helper)"
style="display:none">
<circle
cx="277.60971"
cy="-232.38939"
transform="rotate(84.932981)"
id="circle1035"
style="display:inline;fill:#666666;fill-opacity:0.228916;stroke:none;stroke-width:10.9313;stroke-miterlimit:4;stroke-dasharray:21.8627, 10.9313;stroke-dashoffset:0;stroke-opacity:1"
r="256" />
</g>
<g
transform="translate(458.88987,733.75791)"
id="layer4-9"
inkscape:label="Magic wand"
style="display:inline">
<g
transform="matrix(0.85,0,0,0.85,37.776697,46.855344)"
id="g909">
<text
y="-651.77966"
x="548.3363"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:498.89px;line-height:1.25;font-family:sans-serif;letter-spacing:12.4722px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.999999;stroke-opacity:1"
id="text867"
transform="matrix(0.66397329,0.44974015,-0.45026031,0.66320624,201.94081,-28.649595)"><textPath
xlink:href="#circle1035"
id="textPath869"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:498.89px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro';fill:#ffffff;stroke:none;stroke-width:0.999999;stroke-opacity:1">.......<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:498.89px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro';fill:#808080;stroke-width:0.999999"
id="tspan898">...</tspan></textPath></text>
<path
id="path1551"
d="m 239.35714,172.78831 8.32142,-16.64285 16.64286,-8.32143 -16.64286,-8.32143 -8.32142,-16.64286 -8.32143,16.64286 -16.64286,8.32143 16.64286,8.32143 z m -74.89286,33.28571 13.86558,-27.73636 27.74156,-13.87077 -27.74156,-13.87079 -13.86558,-27.73636 -13.86558,27.73636 -27.74156,13.87079 27.74156,13.87077 z m 183.07143,66.57143 -13.86558,27.73637 -27.74157,13.87079 27.74157,13.87078 13.86558,27.73635 13.86558,-27.73635 27.74156,-13.87078 -27.74156,-13.87079 z m 36.7287,-100.7777 -44.12958,-44.12957 c -3.24534,-3.25576 -7.50488,-4.87844 -11.76441,-4.87844 -4.25954,0 -8.51907,1.62268 -11.76961,4.87844 L 127.73558,316.6034 c -6.50111,6.50113 -6.50111,17.03812 0,23.53405 l 44.12957,44.12957 c 3.25056,3.25056 7.51009,4.87324 11.76442,4.87324 4.25953,0 8.51906,-1.62268 11.76962,-4.87324 L 384.26441,195.39659 c 6.50112,-6.49071 6.50112,-17.03292 0,-23.52884 z m -74.46118,56.80935 -26.47775,-26.47774 45.03973,-45.03973 26.47775,26.47774 z"
style="fill:#ffcc00;fill-opacity:1;stroke-width:0.520089" />
</g>
</g>
</g>
<g
id="g2190"
transform="translate(0,91.928574)">
<text
id="text937"
y="1805.5"
x="1139.7627"
style="font-style:normal;font-weight:normal;font-size:375px;line-height:1.25;font-family:sans-serif;display:inline;fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:2.61155"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:375px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';fill:#e6e6e6;stroke-width:2.61155"
y="1805.5"
x="1139.7627"
id="tspan935"
sodipodi:role="line">ReaLearn</tspan></text>
<text
transform="matrix(0.24932335,0,0,0.24932335,2023.4863,1206.2266)"
style="font-style:normal;font-weight:normal;font-size:800px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect2101);fill:#ff7f2a;fill-opacity:1;stroke:none;filter:url(#filter2177);"
id="text2099"
xml:space="preserve"><tspan
x="2862.8574"
y="1619.663"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:800px;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif'">2</tspan></tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,541 @@
<svg width="377pt" height="227pt" viewBox="0.00 0.00 377.09 227.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns:svgjs="http://svgjs.dev/svgjs">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 223)">
<title>modules</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-223 373.09,-223 373.09,4 -4,4"></polygon>
<g id="clust1" class="cluster">
<title>cluster_realearn</title>
<polygon fill="none" stroke="black" points="8,-64 8,-211 156,-211 156,-64 8,-64"></polygon>
<text text-anchor="middle" x="82" y="-195.8" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">ReaLearn</text>
</g>
<!-- reaper_rs -->
<g id="node1" class="node">
<title>reaper_rs</title>
<polygon fill="none" stroke="black" points="231.5,-108 166.5,-108 166.5,-72 231.5,-72 231.5,-108"></polygon>
<text text-anchor="middle" x="199" y="-86.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">reaper-rs</text>
</g>
<!-- helgoboss_midi -->
<g id="node3" class="node">
<title>helgoboss_midi</title>
<polygon fill="none" stroke="black" points="351.5,-36 250.5,-36 250.5,0 351.5,0 351.5,-36"></polygon>
<text text-anchor="middle" x="301" y="-14.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">helgoboss-midi</text>
</g>
<!-- reaper_rs&#45;&gt;helgoboss_midi -->
<g id="edge6" class="edge">
<title>reaper_rs-&gt;helgoboss_midi</title>
<path fill="none" stroke="black" d="M223.95,-71.88C237.04,-62.89 253.26,-51.76 267.44,-42.03"></path>
<polygon fill="black" stroke="black" points="269.69,-44.73 275.95,-36.19 265.73,-38.96 269.69,-44.73"></polygon>
</g>
<!-- helgoboss_learn -->
<g id="node2" class="node">
<title>helgoboss_learn</title>
<polygon fill="none" stroke="black" points="352,-108 250,-108 250,-72 352,-72 352,-108"></polygon>
<text text-anchor="middle" x="301" y="-86.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">helgoboss-learn</text>
</g>
<!-- helgoboss_learn&#45;&gt;helgoboss_midi -->
<g id="edge7" class="edge">
<title>helgoboss_learn-&gt;helgoboss_midi</title>
<path fill="none" stroke="black" d="M301,-71.7C301,-63.98 301,-54.71 301,-46.11"></path>
<polygon fill="black" stroke="black" points="304.5,-46.1 301,-36.1 297.5,-46.1 304.5,-46.1"></polygon>
</g>
<!-- main -->
<g id="node4" class="node">
<title>main</title>
<polygon fill="none" stroke="black" points="148,-180 94,-180 94,-144 148,-144 148,-180"></polygon>
<text text-anchor="middle" x="121" y="-158.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">main</text>
</g>
<!-- main&#45;&gt;reaper_rs -->
<g id="edge3" class="edge">
<title>main-&gt;reaper_rs</title>
<path fill="none" stroke="black" d="M140.28,-143.7C149.92,-135.05 161.73,-124.45 172.23,-115.03"></path>
<polygon fill="black" stroke="black" points="174.84,-117.39 179.94,-108.1 170.16,-112.18 174.84,-117.39"></polygon>
</g>
<!-- main&#45;&gt;helgoboss_learn -->
<g id="edge4" class="edge">
<title>main-&gt;helgoboss_learn</title>
<path fill="none" stroke="black" d="M148.34,-150.37C174.65,-140.13 215.16,-124.38 247.84,-111.67"></path>
<polygon fill="black" stroke="black" points="249.21,-114.89 257.27,-108.01 246.68,-108.37 249.21,-114.89"></polygon>
</g>
<!-- main&#45;&gt;helgoboss_midi -->
<g id="edge5" class="edge">
<title>main-&gt;helgoboss_midi</title>
<path fill="none" stroke="black" d="M148.3,-159.14C205.44,-154.63 334.55,-140.93 361,-108 373.25,-92.75 369.75,-81.49 361,-64 356.77,-55.53 350.1,-48.25 342.72,-42.15"></path>
<polygon fill="black" stroke="black" points="344.62,-39.2 334.52,-36.01 340.42,-44.8 344.62,-39.2"></polygon>
</g>
<!-- swell_ui -->
<g id="node5" class="node">
<title>swell_ui</title>
<polygon fill="none" stroke="black" points="75.5,-108 16.5,-108 16.5,-72 75.5,-72 75.5,-108"></polygon>
<text text-anchor="middle" x="46" y="-86.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">swell-ui</text>
</g>
<!-- main&#45;&gt;swell_ui -->
<g id="edge2" class="edge">
<title>main-&gt;swell_ui</title>
<path fill="none" stroke="black" d="M102.46,-143.7C93.2,-135.05 81.84,-124.45 71.74,-115.03"></path>
<polygon fill="black" stroke="black" points="74.02,-112.37 64.33,-108.1 69.25,-117.49 74.02,-112.37"></polygon>
</g>
<!-- api -->
<g id="node6" class="node">
<title>api</title>
<polygon fill="none" stroke="black" points="148,-108 94,-108 94,-72 148,-72 148,-108"></polygon>
<text text-anchor="middle" x="121" y="-86.3" font-family="Times,serif" font-size="14.00" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}">api</text>
</g>
<!-- main&#45;&gt;api -->
<g id="edge1" class="edge">
<title>main-&gt;api</title>
<path fill="none" stroke="black" d="M121,-143.7C121,-135.98 121,-126.71 121,-118.11"></path>
<polygon fill="black" stroke="black" points="124.5,-118.1 121,-108.1 117.5,-118.1 124.5,-118.1"></polygon>
</g>
</g>
<style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style></svg>

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,453 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="410" height="410"><style>/* Animations */
@keyframes go-right {
from {
transform: translate(0px, 0px);
}
to {
transform: translate(30px, 0px);
}
}
/* Global appearance */
text {
font-family: sans-serif;
fill: var(--md-grey-900);
}
/* Graphviz diagrams */
.graph text {
font-size: 12px;
}
/* ReaLearn component diagram */
.cluster.level-1 &gt; polygon {
fill: var(--md-grey-50);
}
.cluster.level-2 &gt; polygon {
fill: var(--md-grey-100);
}
.node polygon {
fill: var(--md-grey-200);
}
.node.layer-infrastructure polygon {
fill: var(--layer-infrastructure-color);
}
.node.layer-management polygon {
fill: var(--layer-management-color);
}
.node.layer-processing polygon {
fill: var(--layer-processing-color);
}
.node.layer-base polygon {
fill: var(--layer-base-color);
}
.edge.com-async path {
stroke-dasharray: 5, 2;
}
.edge.dir-control text, .edge.dir-control polygon {
fill: var(--dir-control-color);
}
.edge.dir-feedback text, .edge.dir-feedback polygon {
fill: var(--dir-feedback-color);
}
.edge.dir-control path, .edge.dir-control polygon {
stroke: var(--dir-control-color);
}
.edge.dir-feedback path, .edge.dir-feedback polygon {
stroke: var(--dir-feedback-color);
}
.edge.type-general, .edge.type-midi-general {
opacity: 0.5;
}
.edge {
stroke-width: 2;
}
.edge.type-general path, .edge.type-midi-general path {
stroke-width: 1;
}
/* Onion diagrams */
.layerpart-circle {
fill-opacity: 1.0;
stroke-width: 2;
stroke: var(--md-grey-400);
}
.layerpart-label, .layerpart-secondary-label {
letter-spacing: 1px;
}
.layerpart-secondary-label tspan {
fill: var(--md-grey-500);
}
.arrowpart-label {
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .2));
font-weight: bold;
fill: var(--md-grey-700);
}
.rule-arrow .arrow-pattern-path {
stroke: var(--md-green-900);
}
.rule-arrow .arrow-path {
animation: go-right 2s linear infinite;
stroke-width: 10;
}
.rule-arrow .arrow-head, .rule-arrow .arrow-pattern-head {
fill: var(--md-green-900);
}
/* ReaLearn onion diagram */
.layer-infrastructure .layerpart-circle {
fill: var(--layer-infrastructure-color);
}
.layer-management .layerpart-circle {
fill: var(--layer-management-color);
}
.layer-processing .layerpart-circle {
fill: var(--layer-processing-color);
}
.layer-base .layerpart-circle {
fill: var(--layer-base-color);
}
/* Custom color palette */
:root {
/* Layer colors */
--layer-infrastructure-color: var(--md-yellow-100);
--layer-management-color: var(--md-light-green-100);
--layer-processing-color: var(--md-light-blue-50);
--layer-base-color: var(--md-blue-grey-100);
/* Direction colors */
--dir-control-color: var(--md-amber-900);
--dir-feedback-color: var(--md-cyan-900);
}
/* Material Design color palette */
:root {
--md-red-50: #ffebee;
--md-red-100: #ffcdd2;
--md-red-200: #ef9a9a;
--md-red-300: #e57373;
--md-red-400: #ef5350;
--md-red-500: #f44336;
--md-red-600: #e53935;
--md-red-700: #d32f2f;
--md-red-800: #c62828;
--md-red-900: #b71c1c;
--md-red-a100: #ff8a80;
--md-red-a200: #ff5252;
--md-red-a400: #ff1744;
--md-red-a700: #d50000;
--md-pink-50: #fce4ec;
--md-pink-100: #f8bbd0;
--md-pink-200: #f48fb1;
--md-pink-300: #f06292;
--md-pink-400: #ec407a;
--md-pink-500: #e91e63;
--md-pink-600: #d81b60;
--md-pink-700: #c2185b;
--md-pink-800: #ad1457;
--md-pink-900: #880e4f;
--md-pink-a100: #ff80ab;
--md-pink-a200: #ff4081;
--md-pink-a400: #f50057;
--md-pink-a700: #c51162;
--md-purple-50: #f3e5f5;
--md-purple-100: #e1bee7;
--md-purple-200: #ce93d8;
--md-purple-300: #ba68c8;
--md-purple-400: #ab47bc;
--md-purple-500: #9c27b0;
--md-purple-600: #8e24aa;
--md-purple-700: #7b1fa2;
--md-purple-800: #6a1b9a;
--md-purple-900: #4a148c;
--md-purple-a100: #ea80fc;
--md-purple-a200: #e040fb;
--md-purple-a400: #d500f9;
--md-purple-a700: #aa00ff;
--md-deep-purple-50: #ede7f6;
--md-deep-purple-100: #d1c4e9;
--md-deep-purple-200: #b39ddb;
--md-deep-purple-300: #9575cd;
--md-deep-purple-400: #7e57c2;
--md-deep-purple-500: #673ab7;
--md-deep-purple-600: #5e35b1;
--md-deep-purple-700: #512da8;
--md-deep-purple-800: #4527a0;
--md-deep-purple-900: #311b92;
--md-deep-purple-a100: #b388ff;
--md-deep-purple-a200: #7c4dff;
--md-deep-purple-a400: #651fff;
--md-deep-purple-a700: #6200ea;
--md-indigo-50: #e8eaf6;
--md-indigo-100: #c5cae9;
--md-indigo-200: #9fa8da;
--md-indigo-300: #7986cb;
--md-indigo-400: #5c6bc0;
--md-indigo-500: #3f51b5;
--md-indigo-600: #3949ab;
--md-indigo-700: #303f9f;
--md-indigo-800: #283593;
--md-indigo-900: #1a237e;
--md-indigo-a100: #8c9eff;
--md-indigo-a200: #536dfe;
--md-indigo-a400: #3d5afe;
--md-indigo-a700: #304ffe;
--md-blue-50: #e3f2fd;
--md-blue-100: #bbdefb;
--md-blue-200: #90caf9;
--md-blue-300: #64b5f6;
--md-blue-400: #42a5f5;
--md-blue-500: #2196f3;
--md-blue-600: #1e88e5;
--md-blue-700: #1976d2;
--md-blue-800: #1565c0;
--md-blue-900: #0d47a1;
--md-blue-a100: #82b1ff;
--md-blue-a200: #448aff;
--md-blue-a400: #2979ff;
--md-blue-a700: #2962ff;
--md-light-blue-50: #e1f5fe;
--md-light-blue-100: #466b86;
--md-light-blue-200: #81d4fa;
--md-light-blue-300: #4fc3f7;
--md-light-blue-400: #29b6f6;
--md-light-blue-500: #03a9f4;
--md-light-blue-600: #039be5;
--md-light-blue-700: #0288d1;
--md-light-blue-800: #0277bd;
--md-light-blue-900: #01579b;
--md-light-blue-a100: #80d8ff;
--md-light-blue-a200: #40c4ff;
--md-light-blue-a400: #00b0ff;
--md-light-blue-a700: #0091ea;
--md-cyan-50: #e0f7fa;
--md-cyan-100: #b2ebf2;
--md-cyan-200: #80deea;
--md-cyan-300: #4dd0e1;
--md-cyan-400: #26c6da;
--md-cyan-500: #00bcd4;
--md-cyan-600: #00acc1;
--md-cyan-700: #0097a7;
--md-cyan-800: #00838f;
--md-cyan-900: #006064;
--md-cyan-a100: #84ffff;
--md-cyan-a200: #18ffff;
--md-cyan-a400: #00e5ff;
--md-cyan-a700: #00b8d4;
--md-teal-50: #e0f2f1;
--md-teal-100: #b2dfdb;
--md-teal-200: #80cbc4;
--md-teal-300: #4db6ac;
--md-teal-400: #26a69a;
--md-teal-500: #009688;
--md-teal-600: #00897b;
--md-teal-700: #00796b;
--md-teal-800: #00695c;
--md-teal-900: #004d40;
--md-teal-a100: #a7ffeb;
--md-teal-a200: #64ffda;
--md-teal-a400: #1de9b6;
--md-teal-a700: #00bfa5;
--md-green-50: #e8f5e9;
--md-green-100: #c8e6c9;
--md-green-200: #a5d6a7;
--md-green-300: #81c784;
--md-green-400: #66bb6a;
--md-green-500: #4caf50;
--md-green-600: #43a047;
--md-green-700: #388e3c;
--md-green-800: #2e7d32;
--md-green-900: #1b5e20;
--md-green-a100: #b9f6ca;
--md-green-a200: #69f0ae;
--md-green-a400: #00e676;
--md-green-a700: #00c853;
--md-light-green-50: #f1f8e9;
--md-light-green-100: #dcedc8;
--md-light-green-200: #c5e1a5;
--md-light-green-300: #aed581;
--md-light-green-400: #9ccc65;
--md-light-green-500: #8bc34a;
--md-light-green-600: #7cb342;
--md-light-green-700: #689f38;
--md-light-green-800: #558b2f;
--md-light-green-900: #33691e;
--md-light-green-a100: #ccff90;
--md-light-green-a200: #b2ff59;
--md-light-green-a400: #76ff03;
--md-light-green-a700: #64dd17;
--md-lime-50: #f9fbe7;
--md-lime-100: #f0f4c3;
--md-lime-200: #e6ee9c;
--md-lime-300: #dce775;
--md-lime-400: #d4e157;
--md-lime-500: #cddc39;
--md-lime-600: #c0ca33;
--md-lime-700: #afb42b;
--md-lime-800: #9e9d24;
--md-lime-900: #827717;
--md-lime-a100: #f4ff81;
--md-lime-a200: #eeff41;
--md-lime-a400: #c6ff00;
--md-lime-a700: #aeea00;
--md-yellow-50: #fffde7;
--md-yellow-100: #fff9c4;
--md-yellow-200: #fff59d;
--md-yellow-300: #fff176;
--md-yellow-400: #ffee58;
--md-yellow-500: #ffeb3b;
--md-yellow-600: #fdd835;
--md-yellow-700: #fbc02d;
--md-yellow-800: #f9a825;
--md-yellow-900: #f57f17;
--md-yellow-a100: #ffff8d;
--md-yellow-a200: #ffff00;
--md-yellow-a400: #ffea00;
--md-yellow-a700: #ffd600;
--md-amber-50: #fff8e1;
--md-amber-100: #ffecb3;
--md-amber-200: #ffe082;
--md-amber-300: #ffd54f;
--md-amber-400: #ffca28;
--md-amber-500: #ffc107;
--md-amber-600: #ffb300;
--md-amber-700: #ffa000;
--md-amber-800: #ff8f00;
--md-amber-900: #ff6f00;
--md-amber-a100: #ffe57f;
--md-amber-a200: #ffd740;
--md-amber-a400: #ffc400;
--md-amber-a700: #ffab00;
--md-orange-50: #fff3e0;
--md-orange-100: #ffe0b2;
--md-orange-200: #ffcc80;
--md-orange-300: #ffb74d;
--md-orange-400: #ffa726;
--md-orange-500: #ff9800;
--md-orange-600: #fb8c00;
--md-orange-700: #f57c00;
--md-orange-800: #ef6c00;
--md-orange-900: #e65100;
--md-orange-a100: #ffd180;
--md-orange-a200: #ffab40;
--md-orange-a400: #ff9100;
--md-orange-a700: #ff6d00;
--md-deep-orange-50: #fbe9e7;
--md-deep-orange-100: #ffccbc;
--md-deep-orange-200: #ffab91;
--md-deep-orange-300: #ff8a65;
--md-deep-orange-400: #ff7043;
--md-deep-orange-500: #ff5722;
--md-deep-orange-600: #f4511e;
--md-deep-orange-700: #e64a19;
--md-deep-orange-800: #d84315;
--md-deep-orange-900: #bf360c;
--md-deep-orange-a100: #ff9e80;
--md-deep-orange-a200: #ff6e40;
--md-deep-orange-a400: #ff3d00;
--md-deep-orange-a700: #dd2c00;
--md-brown-50: #efebe9;
--md-brown-100: #d7ccc8;
--md-brown-200: #bcaaa4;
--md-brown-300: #a1887f;
--md-brown-400: #8d6e63;
--md-brown-500: #795548;
--md-brown-600: #6d4c41;
--md-brown-700: #5d4037;
--md-brown-800: #4e342e;
--md-brown-900: #3e2723;
--md-grey-50: #fafafa;
--md-grey-100: #f5f5f5;
--md-grey-200: #eeeeee;
--md-grey-300: #e0e0e0;
--md-grey-400: #bdbdbd;
--md-grey-500: #9e9e9e;
--md-grey-600: #757575;
--md-grey-700: #616161;
--md-grey-800: #424242;
--md-grey-900: #212121;
--md-blue-grey-50: #eceff1;
--md-blue-grey-100: #cfd8dc;
--md-blue-grey-200: #b0bec5;
--md-blue-grey-300: #90a4ae;
--md-blue-grey-400: #78909c;
--md-blue-grey-500: #607d8b;
--md-blue-grey-600: #546e7a;
--md-blue-grey-700: #455a64;
--md-blue-grey-800: #37474f;
--md-blue-grey-900: #263238;
--md-black: #000000;
--md-white: #ffffff;
--md-dark-text-primary: rgba(0, 0, 0, 0.87);
--md-dark-text-secondary: rgba(0, 0, 0, 0.54);
--md-dark-text-disabled: rgba(0, 0, 0, 0.38);
--md-dark-text-dividers: rgba(0, 0, 0, 0.12);
--md-light-text-primary: rgba(255, 255, 255, 1);
--md-light-text-secondary: rgba(255, 255, 255, 0.7);
--md-light-text-disabled: rgba(255, 255, 255, 0.5);
--md-light-text-dividers: rgba(255, 255, 255, 0.12);
--md-dark-icons-active: rgba(0, 0, 0, 0.54);
--md-dark-icons-inactive: rgba(0, 0, 0, 0.38);
--md-light-icons-active: rgba(255, 255, 255, 1);
--md-light-icons-inactive: rgba(255, 255, 255, 0.5);
}
</style><defs><pattern x="0" y="0" width="30" height="20" patternUnits="userSpaceOnUse" id="SvgjsPattern1008"><g class="rule-arrow"><line x1="0" y1="3.5" x2="10" y2="3.5" stroke-width="1" stroke="black" class="arrow-pattern-path"></line><polygon points="10,0 20,3.5 10,7" class="arrow-pattern-head"></polygon></g></pattern><marker markerWidth="10" markerHeight="7" refX="5" refY="3.5" viewBox="0 0 10 7" orient="auto"><polygon points="0,0 10,3.5 0,7" class="arrow-head"></polygon></marker><path d="M35 205A-170 -170 0 0 1 375 205 " id="SvgjsPath1000"></path><path d="M25 205A-180 -180 0 0 0 385 205 " id="SvgjsPath1001"></path><path d="M25 205A-180 -180 0 0 0 385 205 " id="SvgjsPath1002"></path><path d="M25 205A-180 -180 0 0 0 385 205 " id="SvgjsPath1003"></path><path d="M25 205A-180 -180 0 0 0 385 205 " id="SvgjsPath1004"></path><path d="M85 205A-120 -120 0 0 1 325 205 " id="SvgjsPath1005"></path><path d="M135 205A-70 -70 0 0 1 275 205 " id="SvgjsPath1006"></path><path d="M185 205A-20 -20 0 0 1 225 205 " id="SvgjsPath1007"></path><path d="M-95 205L305 205 " id="SvgjsPath1009"></path><clipPath id="SvgjsClipPath1010"><polygon points="5,195 205,195 205,215 12,215"></polygon></clipPath></defs><g class="layer-infrastructure"><circle r="200" cx="205" cy="205" fill="none" stroke="black" class="layerpart-circle"></circle><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1000" text-anchor="middle" startOffset="50%" font-size="15" class="layerpart-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">infrastructure</tspan></textPath></text><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1001" text-anchor="middle" startOffset="12.5%" font-size="15" class="layerpart-secondary-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">GUI</tspan></textPath></text><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1002" text-anchor="middle" startOffset="37.5%" font-size="15" class="layerpart-secondary-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">API</tspan></textPath></text><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1003" text-anchor="middle" startOffset="62.5%" font-size="15" class="layerpart-secondary-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">Persistence</tspan></textPath></text><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1004" text-anchor="middle" startOffset="87.5%" font-size="15" class="layerpart-secondary-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">Server</tspan></textPath></text></g><g class="layer-management"><circle r="150" cx="205" cy="205" fill="none" stroke="black" class="layerpart-circle"></circle><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1005" text-anchor="middle" startOffset="50%" font-size="15" class="layerpart-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">management</tspan></textPath></text></g><g class="layer-processing"><circle r="100" cx="205" cy="205" fill="none" stroke="black" class="layerpart-circle"></circle><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1006" text-anchor="middle" startOffset="50%" font-size="15" class="layerpart-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">processing</tspan></textPath></text></g><g class="layer-base"><circle r="50" cx="205" cy="205" fill="none" stroke="black" class="layerpart-circle"></circle><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1007" text-anchor="middle" startOffset="50%" font-size="15" class="layerpart-label" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="0" x="0" svgjs:data="{&quot;newLined&quot;:true}">base</tspan></textPath></text></g><g class="rule-arrow"><g clip-path="url(&quot;#SvgjsClipPath1010&quot;)"><path d="M-95 205L305 205 " class="arrow-path" stroke-width="10" stroke="url(&quot;#SvgjsPattern1008&quot;)"></path></g><text svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><textPath href="#SvgjsPath1009" class="arrowpart-label" font-size="15" text-anchor="middle" startOffset="50%" svgjs:data="{&quot;leading&quot;:&quot;1.3&quot;}"><tspan dy="-10">may use code in</tspan></textPath></text></g></svg>

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,2 @@
The list of tested controllers is now part of the Wiki.
You can find it link:https://github.com/helgoboss/helgobox/wiki/ReaLearn-Controllers[here].
@@ -0,0 +1,6 @@
= Helgobox Reference
:experimental:
This reference is written in AsciiDoc and follows the directory conventions of the documentation site generator link:https://antora.org/[Antora].
A good place to start is link:modules/ROOT/pages/introduction.adoc[].
@@ -0,0 +1,10 @@
name: helgobox
title: Helgobox Reference
version: ~
nav:
- modules/ROOT/nav.adoc
start_page: introduction.adoc
asciidoc:
attributes:
# For making menu and button macros work
experimental: true
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

@@ -0,0 +1,18 @@
* xref:introduction.adoc[]
* xref:products.adoc[]
* xref:installation.adoc[]
* xref:key-concepts.adoc[]
* xref:plug-in.adoc[]
** xref:plug-in/user-interface.adoc[]
*** xref:plug-in/user-interface/welcome-dialog.adoc[]
*** xref:plug-in/user-interface/menu-bar.adoc[]
* xref:app.adoc[]
** xref:app/user-interface.adoc[]
*** xref:app/user-interface/general.adoc[]
*** xref:app/user-interface/title-bar.adoc[]
*** xref:app/user-interface/navigation-bar.adoc[]
*** xref:app/user-interface/settings-dialog.adoc[]
*** xref:app/user-interface/keyboard-shortcuts.adoc[]
*** xref:app/user-interface/cli.adoc[]
* xref:reaper-actions.adoc[]
* xref:configuration-files.adoc[]
@@ -0,0 +1,88 @@
= Helgobox App
.What is the Helgobox App?
____
include::partial$app-desc.adoc[]
____
Have you created an xref:key-concepts.adoc#instance[] of the xref:plug-in.adoc[] already? Good. Then you can connect to it with the _Helgobox App_.
You can run the app in two ways: *Embedded* or *Remote*
[[app-embedded-mode]]
== Embedded mode
Each Helgobox xref:key-concepts.adoc#instance[] can display its own xref:app.adoc[] window, directly embedded into REAPER:
. Open the desired xref:plug-in.adoc[] instance
. Press menu:Menu[Show App]
Embedded mode is the recommended way to run the app. It offers seamless integration with REAPER.
[[app-remote-mode]]
== Remote mode
There's an additional way to use the app: To run it as a separate program that connects with REAPER over a network connection.
=== Use cases
Running the app in remote mode opens up interesting possibilities.
Crash protection::
You can start the app on the same machine, but outside of REAPER.
If it crashes for some reason, only the app itself will crash.
REAPER and the xref:plug-in.adoc[] will continue running. It's similar to running plug-ins in REAPER in bridged mode. This could be interesting for live scenarios.
Additional views::
You can open additional app windows on the same machine and connect them to the same xref:key-concepts.adoc#instance[]. This gives you multiple views on the same instance.
Performance optimization::
You can run the app on an extra computer and connect it to REAPER on the main machine. This way, you can be sure that the app doesn't take any valuable processing power away from REAPER and the xref:plug-in.adoc[].
Touch screen operation::
Maybe your main machine is a powerful Mac mini standing somewhere further away from you. You could take a Windows tablet (and in the future an iOS or Android tablet) and run the app there, connecting to your main machine.
Running Playtime on Linux (temporarily)::
Playtime's Linux support is currently limited to remote mode. Embedded mode is still in the works.
=== How to do it
Here's what you need to do to run the app in remote mode.
==== Starting the server
To allow connections to Helgobox from computers in the same network, you need to start the xref:plug-in/user-interface/menu-bar.adoc#server[Helgobox Server].
. Open the xref:plug-in.adoc[]
. Press menu:Menu[Server > Enable and start!]
You need to do this only once. Next time you start REAPER and Helgobox, the server will start automatically!
==== Starting the app
Just like the plug-in, the app is part of the Helgobox installation and is located in your REAPER resource directory:
. Open an arbitrary instance of the xref:plug-in.adoc[]
+
.Hello, Playtime for Linux testers!
TIP: If you are here because you want to try Playtime for Linux *Stage 1*, pressing the image:playtime::screenshots/playtime-toolbar-icon.png[Playtime,width=50, pdfwidth=8mm] button should already have created a "Playtime" track for you, along with a xref:plug-in.adoc[] instance. Simply open that existing one!
. Press menu:Menu[Server > Open app folder]
. Start the app executable:
[horizontal]
Windows:: `helgobox.exe`
macOS:: `Contents/MacOS/helgobox`
Linux:: `helgobox`
By default, the app connects to the REAPER process running on the _same machine_ (to the xref:plug-in/user-interface/menu-bar.adoc#server[Helgobox Server] running in that process, to be accurate). You can change that by running the app with special xref:app/user-interface/cli.adoc[command line arguments].
Also by default, the app connects to the first xref:key-concepts.adoc#instance[] running in that REAPER process. You can switch to another instance (within the same process) by pressing the xref:app/user-interface/navigation-bar.adoc#navbar-pick-instance[] button or by running the app with special xref:app/user-interface/cli.adoc[command line arguments].
.Copying the app directory somewhere else
[CAUTION]
====
You may copy the app directory to another location or even to another computer. However, you should renew your copy whenever you update Helgobox! An update often contains both a new version of the xref:plug-in.adoc[] **and** a new version of the xref:app.adoc[].
If you connect the app to a plug-in and the versions don't match, you will see the following error message:
> Host API version doesn't match
====
@@ -0,0 +1,8 @@
= User interface
Unlike the xref:plug-in.adoc[], the App offers a modern and fancy user interface.
At the moment, it primarily provides the user interface for xref:playtime::introduction.adoc[Playtime], but it will contain more stuff in the future.
.App window
image::generated/screenshots/main/home-screen.png[]
@@ -0,0 +1,9 @@
= About dialog
This dialog appears when you click the xref:app/user-interface/help-menu.adoc#title-bar-about[] button in the help menu.
image::generated/screenshots/main/about.png[]
The version number displayed here is the version of the xref:app.adoc[], not the one of the controlled xref:plug-in.adoc[]! _App_ and _plug-in_ are often updated together, but that's not always the case. They can evolve independently.
The app version number is most relevant when running the app in xref:app.adoc#app-remote-mode[].
@@ -0,0 +1,58 @@
= Command line interface
When running in xref:app.adoc#app-remote-mode[], the app session can optionally be configured using command line arguments.
== Synopsis
*helgobox* [_OPTIONS_]
== Options
--connection=<URL>::
URL that decides how the app connects to the xref:plug-in.adoc[].
+
.Connection examples
[cols="1,2"]
|===
|
`grpc:://localhost:39051` +
`grpc:://127.0.0.1:39051`
|
Connects to the plug-in running on the same machine, assuming a xref:configuration-files.adoc#realearn-ini[standard server configuration] (`server_grpc_port=39051`).
This is the default if the connection option is omitted.
|
`grpc:://winpc:39051` +
`grpc:://192.168.1.47:39051`
|
Connects to the plug-in running on the machine with the host name `winpc` or the IP address 192.168.1.47.
|===
--location::
Path that decides which page is shown initially.
+
This is not a file system path. It's comparable to the path of a URL that you would see in a web browser's address bar.
+
.Location examples
[cols="1,2"]
|===
|
`/instance/apc/projection`
|
Opens the xref:realearn::user-interface/projection.adoc[projection page] for the xref:key-concepts.adoc#instance[] with xref:key-concepts.adoc#instance-key[] `apc`.
|
`/instance/3/playtime`
|
Opens the xref:playtime::user-interface.adoc[Playtime] page for the xref:key-concepts.adoc#instance[] with xref:key-concepts.adoc#instance-id[] *3*.
Numbers are always interpreted as instance IDs and strings as instance keys. Normally, you want to use an xref:key-concepts.adoc#instance-key[instance key] to refer to the desired instance, because instance IDs are likely to change after restarting REAPER.
|===
--help::
Displays an overview of all supported command line options.
@@ -0,0 +1,59 @@
= General usage
This page describes the basic usage of common user interface elements in the Helgobox app.
[[drag-field]]
== Drag field
image::playtime::generated/screenshots/elements/toolbar/tempo.png[]
A drag field allows you to adjust numeric values in various ways.
include::partial$app/user-interface/interactions/mouse-dragging.adoc[]
include::partial$app/user-interface/interactions/mouse-wheel-scrolling.adoc[]
include::partial$app/user-interface/interactions/touchpad-panning.adoc[]
include::partial$app/user-interface/interactions/text-entry.adoc[]
include::partial$app/user-interface/interactions/reset-to-default.adoc[]
include::partial$app/user-interface/interactions/fine-adjustment.adoc[]
== Knob
image::playtime::generated/screenshots/elements/toolbar/play-rate.png[]
A knob allows you to adjust numeric values in various ways.
include::partial$app/user-interface/interactions/mouse-dragging.adoc[]
include::partial$app/user-interface/interactions/mouse-wheel-scrolling.adoc[]
include::partial$app/user-interface/interactions/touchpad-panning.adoc[]
include::partial$app/user-interface/interactions/text-entry.adoc[]
include::partial$app/user-interface/interactions/reset-to-default.adoc[]
include::partial$app/user-interface/interactions/fine-adjustment.adoc[]
== Slider
image::playtime::generated/screenshots/elements/track-panel/volume.png[]
A slider allows you to adjust numeric values in various ways.
include::partial$app/user-interface/interactions/mouse-dragging.adoc[]
include::partial$app/user-interface/interactions/mouse-wheel-scrolling.adoc[]
include::partial$app/user-interface/interactions/touchpad-panning.adoc[]
include::partial$app/user-interface/interactions/reset-to-default.adoc[]
== Search list
image::playtime::generated/screenshots/main/sequences.png[]
Search lists allow you to pick an item from a potentially large list.
icon:search[] Search::
Simply enter text to drill the list down to items matching your search text.
icon:keyboard-o[] Navigate::
Press kbd:[↑] or kbd:[↓] to navigate within the list of items.
↕ Scroll::
Scroll within the list using the scrollbar on the right or using the mousewheel.
icon:mouse-pointer[] Select::
Click the item or press kbd:[Enter] to select it.
@@ -0,0 +1,13 @@
= Help menu
This menu appears when clicking the xref:app/user-interface/title-bar.adoc#title-bar-help[] button in the window title bar.
include::partial$generated/menus/help/open-helgobox-reference.adoc[]
include::partial$generated/menus/help/open-helgobox-website.adoc[]
include::partial$generated/menus/help/highlight-screen-areas.adoc[]
include::partial$generated/menus/help/about.adoc[]
See xref:app/user-interface/about-dialog.adoc[].
@@ -0,0 +1,44 @@
= Keyboard shortcuts
Within the app, you can use the following keyboard shortcuts.
|===
|Shortcut |Purpose
|[[esc,Esc]] kbd:[Esc]
|Hides the app window.
Hiding the window doesn't completely unload the app, it really just hides the window.
|kbd:[F]
|Toggles full-screen mode.
|kbd:[F1]
|Opens online help for the element that is currently under the mouse cursor.
|kbd:[Shift+Cmd/Ctrl+H]
|Executes the REAPER action xref:helgobox::reaper-actions.adoc#toggle-app-focus[].
|===
Depending on the currently selected page, more keyboard shortcuts are available:
- xref:playtime::user-interface/keyboard-shortcuts.adoc[Playtime shortcuts]
[TIP]
====
**Normal REAPER's keyboard shortcuts are generally disabled when the app is focused!**
This prevents conflicts and ensures flexibility for adding more app shortcuts in the future.
If you want to use a certain REAPER shortcut while the app is focused, you must make it global:
. Open menu:Actions[Show action list...]
. Press btn:[Find shortcut...]
. Press the shortcut key
+
The action list should jump to the action mapped to that key.
. Double-click the desired shortcut in the "Shortcuts for selected action" list
. Change the property "Scope" to **Global**
. Press btn:[OK]
====
@@ -0,0 +1,22 @@
= Navigation bar
The bar on the left is the _Navigation bar_.
Its main purpose is to switch between different pages.
You can show or hide it using the xref:app/user-interface/title-bar.adoc#title-bar-toggle-nav-bar[] button in the xref:app/user-interface/title-bar.adoc[].
include::partial$generated/elements/navbar/home.adoc[]
include::partial$generated/elements/navbar/projection.adoc[]
include::partial$generated/elements/navbar/playtime.adoc[]
include::partial$generated/elements/navbar/enable-disable-global-control.adoc[]
See xref:realearn::further-concepts/instance.adoc#auto-units[].
include::partial$generated/elements/navbar/show-helgobox-plugin.adoc[]
include::partial$generated/elements/navbar/pick-instance.adoc[]
This is only displayed if you run the app in xref:app.adoc#app-remote-mode[].
@@ -0,0 +1,50 @@
= Settings dialog
The dialog allows you to adjust the majority of global settings for Helgobox and its contained products.
You can open it by pressing the xref:app/user-interface/title-bar.adoc#title-bar-settings[] button in the xref:app/user-interface/title-bar.adoc[].
image::generated/screenshots/main/settings.png[]
For a description of the product-specific settings, see:
* xref:realearn::user-interface/settings-dialog.adoc[ReaLearn settings]
* xref:playtime:ROOT:user-interface/dialogs/settings-dialog.adoc[Playtime settings]
== Appearance
include::partial$generated/elements/settings/overall-size.adoc[]
include::partial$generated/elements/settings/roundness.adoc[]
.For Playtime users
TIP: If you want slot cells with rounded corners, play with the xref:playtime:ROOT:user-interface/dialogs/settings-dialog.adoc#settings-cell-color-position[] setting!
include::partial$generated/elements/settings/prefer-tidy-appearance.adoc[]
include::partial$generated/elements/settings/display-development-status-hints.adoc[]
include::partial$generated/elements/settings/display-tooltip-if-help-panel-hidden.adoc[]
include::partial$generated/elements/settings/display-license-info.adoc[]
include::partial$generated/elements/settings/prefer-native-popup-menus.adoc[]
include::partial$generated/elements/settings/theme-mode.adoc[]
include::partial$generated/elements/settings/use-context-coloring.adoc[]
include::partial$generated/elements/settings/use-host-colors.adoc[]
include::partial$generated/elements/settings/contrast.adoc[]
include::partial$generated/elements/settings/custom-color-rendering.adoc[]
include::partial$generated/elements/settings/color-scheme.adoc[]
== Title bar
include::partial$generated/elements/settings/dim-opacity.adoc[]
== Shortcuts
include::partial$generated/elements/settings/hide-window-when-escape-pressed.adoc[]
@@ -0,0 +1,55 @@
= Title bar
The bar on the top of the app window is the _Title bar_.
It primarily provides general functions, such as window controls, access to settings, and quick access to the REAPER transport.
image::generated/screenshots/elements/area/window-title-bar-0.png[]
include::partial$generated/elements/title-bar/close-window.adoc[]
This has the same effect as pressing xref:helgobox::plug-in/user-interface/menu-bar.adoc#close-app[].
include::partial$generated/elements/title-bar/full-screen.adoc[]
include::partial$generated/elements/title-bar/move-window.adoc[]
include::partial$generated/elements/title-bar/toggle-nav-bar.adoc[]
include::partial$generated/elements/title-bar/theme-mode.adoc[]
include::partial$generated/elements/title-bar/dim.adoc[]
The opacity of the opaque window can be adjusted via xref:app/user-interface/settings-dialog.adoc#settings-dim-opacity[].
include::partial$generated/elements/title-bar/settings.adoc[]
See xref:app/user-interface/settings-dialog.adoc[].
include::partial$generated/elements/title-bar/refresh.adoc[]
include::partial$generated/elements/title-bar/undo.adoc[]
include::partial$generated/elements/title-bar/redo.adoc[]
include::partial$generated/elements/title-bar/theme-switcher.adoc[]
Themes are simply pre-selected combinations of various appearance settings.
Once youve selected a theme, you can further customize it by adjusting the settings.
include::partial$generated/elements/title-bar/panic-midi.adoc[]
include::partial$generated/elements/title-bar/save-project.adoc[]
include::partial$generated/elements/title-bar/play-arrangement.adoc[]
include::partial$generated/elements/title-bar/stop-arrangement.adoc[]
include::partial$generated/elements/title-bar/pause-arrangement.adoc[]
include::partial$generated/elements/title-bar/help.adoc[]
See xref:app/user-interface/help-menu.adoc[].
include::partial$generated/elements/title-bar/helgobox-info.adoc[]
See xref:key-concepts.adoc#instance-id[].
@@ -0,0 +1,34 @@
= Configuration files
Helgobox creates and/or reads a few files in REAPER's resource directory.
For product-specific configuration files, please refer to:
* xref:realearn::configuration-files.adoc[ReaLearn configuration files]
* xref:playtime::configuration-files.adoc[Playtime configuration files]
Helgobox itself maintains the following files:
`Data/helgoboss`:: Directory which contains data such as presets or resources that need to be distributed via ReaPack
`Data/helgoboss/archives`:: Directory which contains archives e.g. the compressed app, distributed via ReaPack
`Data/helgoboss/doc`:: Contains offline documentation as PDFs
`Helgoboss`:: Directory which contains user-specific or device-specific data, not touched via ReaPack
`licensing.json`:: Contains license keys
`Helgoboss/App/bin`:: Contains the uncompressed xref:app.adoc[], if installed
`Helgoboss/App/etc/settings.json`:: Contains the global settings for Helgobox and all of its contained products
`Helgoboss/Pot/previews`:: Directory which contains previews recorded by xref:products.adoc#pot-browser[Pot Browser]
`Helgoboss/Server/certificates`:: Contains a list of certificates and corresponding private keys in order to allow encrypted communication with ReaLearn Companion and App.
[[realearn-ini]] `Helgoboss/ReaLearn/realearn.ini`:: Very basic global configuration.
The reference to ReaLearn is there just for historical reasons.
Most properties in here affect Helgobox as a whole.
+
Currently supported properties: `server_enabled`, `server_http_port`, `server_https_port`, `server_grpc_port`, `companion_web_app_url`, `showed_welcome_screen`, `background_colors_enabled`
@@ -0,0 +1,186 @@
= Installation
:plugin-name: "VSTi: Helgobox - ReaLearn & Playtime (Helgoboss)"
:package-name: "Helgobox: ReaLearn & Playtime"
Helgobox is provided as https://reapack.com/[ReaPack] package.
ReaPack is a popular 3rd-party package manager for REAPER that makes installing add-ons easy and keeps your installation up to date effortlessly.
== System requirements
Please check below system requirements before attempting to install Helgobox!
=== REAPER
* Playtime needs REAPER 7.23 or later
* ReaLearn works acceptably with older REAPER versions, but it works better with REAPER 7.23 or later
[[windows]]
=== Windows
* xref:plug-in.adoc[] needs Windows 7 or later
* xref:app.adoc[] needs Windows 8 or later
[[macos]]
=== macOS
* xref:plug-in.adoc[] needs macOS 10.12 or later
* xref:app.adoc[] needs macOS 10.15 or later
* For macOS 10.14 or later, all below-mentioned installation options should work
* **For macOS 10.13 or earlier, installation via installer is not supported.
You need to install via ReaPack!**
[[linux]]
=== Linux
* On x64 architecture: Needs at least glibc v2.31 (for example, Ubuntu 20+, Debian 11+)
* On arm64 architecture: Needs at least glibc v2.35 (for example, Ubuntu 22+, Debian 12+)
* **Installation via installer is not supported.
You need to install via ReaPack!**
* Needs libxdo.
You can install it like this:
+
[source,shell]
.Debian, Ubuntu
----
sudo apt-get install -y libxdo-dev
----
+
[source,shell]
.openSUSE
----
sudo zypper install xdotool
----
* Other dependencies that you might need to install manually, depending on your Linux distribution: `libx11`, `libstdc++`, `libudev`
* If {plugin-name} isn't available after installation, REAPER failed to scan it. And that is most likely due to a missing dependency. In that case, please link:https://github.com/helgoboss/helgobox/issues/503#issuecomment-1320964181[try this to analyze the issue] and send the result to info@helgoboss.org.
IMPORTANT: If you want to use a _Stream Deck_ controller with ReaLearn on Linux, xref:realearn::sources/stream-deck.adoc#linux[more setup] is necessary.
NOTE: A more detailed system compatibility table can be found link:https://www.helgoboss.org/projects/helgobox#requirements[here].
== Installing Helgobox
Please choose:
[loweralpha]
. <<installer>>
. <<i-have-reapack>>
. <<i-want-to-install-reapack>>
. <<install-without-reapack>>
[[installer]]
=== I want an installer 👍
For users who don't have ReaPack installed already, there's a **convenient installer** that automatically installs both ReaPack and Helgobox.
It gets you up and running in no time, supporting even portable REAPER installations!
You can use it if you have Windows 7+ or macOS 10.14+.
Simply press the following link and follow the instructions: link:https://reaboot.com/install/https%3A%2F%2Fraw.githubusercontent.com%2Fhelgoboss%2Fhelgobox%2Fmaster%2Freaboot.json[Install Helgobox]
[[i-have-reapack]]
=== I have ReaPack and want to use it to install Helgobox
Here's how you can install Helgobox via ReaPack:
. In REAPER, select menu:Extensions[ReaPack > Import repositories…]
. Copy and paste the following repository URL into the text area:
+
https://github.com/helgoboss/reaper-packages/raw/master/index.xml
+
. Select menu:Extensions[ReaPack > Browse packages…]
. Search for `helgobox`
. Right mouse click on the package {package-name} and choose menu:Install…[]
. Press btn:[OK] or btn:[Apply]
. Restart REAPER
[[i-want-to-install-reapack]]
=== I don't have ReaPack but want to use it to install Helgobox
. Install ReaPack, following the link:https://reapack.com/user-guide[installation section of its user guide]
. Restart REAPER
. Follow the instructions in <<i-have-reapack>>
[[install-without-reapack]]
=== I want to install Helgobox manually, without ReaPack
If you are more the download type of person, you can find the latest `dll`, `dylib` and `so` files here at GitHub on the https://github.com/helgoboss/helgobox/releases[releases page] for manual installation.
You also must install Helgobox manually if you plan to use it in both REAPER for Windows 32-bit and REAPER for Windows 64-bit because then it's important to use two separate VST plug-in directories.
== Validating the installation
You know that Helgobox is installed successfully if you see the menu menu:Extensions[Helgobox].
In addition, you should see a plug-in entry {plugin-name} after right-clicking the empty area of REAPER's track panel and choosing menu:Insert virtual instrument on new track...[].
NOTE: On Helgobox for Linux, the extension menu entry doesn't exist yet.
But the plug-in should be there.
== Troubleshooting
=== Helgobox plug-in doesn't appear in the list of plug-ins
If the plug-in {plugin-name} doesn't appear in the list of plug-ins, please proceed as follows:
. If you are on Linux, make sure to follow the <<linux, installation instructions for Linux>>!
. Make sure that Helgobox runs as native plug-in!
** By default, each plug-in runs as native plug-in.
If not, you probably changed the configuration at some point.
** You can fix that by right-clicking {plugin-name} in the plug-in list and select menu:Run as[Native only (prevent bridging)].
** It's technically impossible to run Helgobox as a bridged plug-in!
TIP: If none of these suggestions help, link:https://github.com/helgoboss/helgobox/issues/new/choose[please report a bug]!
[[updating-helgobox]]
== Updating Helgobox
Helgobox development moves fast!
To take advantage of the latest features, improvements and fixes, you should check the link:https://www.helgoboss.org/projects/helgobox[Helgobox homepage] for updates from time to time.
Here's how you can install the latest stable Helgobox version:
. Run menu:Extensions[ReaPack > Synchronize packages]
** ReaPack will show you a summary at the end, which tells you whether a new Helgobox version has been installed.
. Restart REAPER
If <<installer,supported on your system>>, you can alternatively just run the link:https://www.helgoboss.org/projects/helgobox#download[Helgobox installer app] again.
[[downgrading-helgobox]]
== Downgrading Helgobox
Downgrading is easily possible via ReaPack as well.
.Be careful when saving projects after updates or downgrades!
[CAUTION]
====
It is not guaranteed that projects saved with newer versions can still be opened with older versions of Helgobox! Even if it works, saving a project with that older version might overwrite changes that you made in the newer version. That's why Helgobox will warn you in this case.
If your project is crucial, it is recommended to make a backup before re-saving it with another version.
====
. menu:Extensions[ReaPack > Browse packages...]
. Right-click the package {package-name} and navigate to the submenu menu:Versions[]
. Select the desired old version
. Press btn:[OK] or btn:[Apply]
. Restart REAPER
[[pre-releases]]
== Testing new features and improvements
If you want to get access to cutting-edge but untested versions of Helgobox, you can install Helgobox pre-releases.
=== Install a specific pre-release of Helgobox
. menu:Extensions[ReaPack > Browse packages...]
. Right-click the package {package-name} and navigate to the submenu menu:Versions[]
. Select the desired pre-release version (versions containing `-pre` or `-rc`)
. Press btn:[OK] or btn:[Apply]
. Restart REAPER
=== Enable pre-releases globally
. menu:Extensions[ReaPack > Manage repositories]
. menu:Options…[Enable pre-releases globally (bleeding edge)]
. After that, whenever you synchronize packages, you will get the latest stuff.
@@ -0,0 +1,19 @@
= Introduction
include::helgobox::partial$intro-header.adoc[]
|===
|Last update of text: |`2025-03-15 (v2.18.0)`
|Last update of screenshots: |`2025-03-15 (v2.18.0)`
|===
link:https://www.helgoboss.org/projects/helgobox[Helgobox] is an add-on for link:https://www.reaper.fm[REAPER] that unites xref:products.adoc[a few creative tools] under one roof, most importantly link:https://www.helgoboss.org/projects/realearn[ReaLearn] and link:https://www.helgoboss.org/projects/playtime[Playtime].
It consists of two technical components:
xref:plug-in.adoc[]::
include::partial$plug-in-desc.adoc[]
xref:app.adoc[]::
include::partial$app-desc.adoc[]
include::partial$product-specific-info.adoc[]
@@ -0,0 +1,27 @@
= Key concepts
[[instance]]
== Instance
Helgobox is an instrument plug-in.
That means you can add multiple instances of it, just as you would add multiple instances of a synth or effect.
For example, you could place one instance on the monitoring FX chain and two instances somewhere in your project.
[[instance-id]]
== Instance ID
A *randomly assigned*, *non-persistent* identifier that identifies a particular <<instance>> and is *guaranteed to be unique* within one REAPER session.
CAUTION: This ID can change after a restart of REAPER! If you are looking for something that doesn't change, use the <<instance-key>>.
[[instance-key]]
== Instance key
A *user-defined*, *persistent* identifier that identifies a particular <<instance>>.
The instance key gets relevant if you want to connect to an instance from an xref:app.adoc[] running in xref:app.adoc#app-remote-mode[].
You can change the instance key of an instance by changing the xref:realearn::further-concepts/unit.adoc#unit-key[] of the instance's xref:realearn::key-concepts.adoc#unit[main unit] -- they are the same.
.Make your instance keys unique!
CAUTION: Because the instance key is user-defined, uniqueness can't be guaranteed. For example, if you just copy and paste a Helgobox FX instance, you end up with two instances that have the same key. You should avoid this.
@@ -0,0 +1,27 @@
= Helgobox Plug-In
.What is the Helgobox Plug-In?
____
include::partial$plug-in-desc.adoc[]
It is complemented by the xref:app.adoc[].
____
== Adding a new plug-in instance
The plug-in is fired up just like any other VST instrument in REAPER: By adding an instance of it to an FX chain:
. Right-click the empty space in REAPER's track control panel
. Select menu:Insert virtual instrument on new track...[]
. Double-click entry "VSTi: Helgobox - ReaLearn & Playtime (Helgoboss)"
Initially, you see the xref:plug-in/user-interface.adoc[plug-in window].
== Opening an existing plug-in instance
To open an existing plug-in instance:
1. Scroll to the REAPER track which contains the instance.
2. Press the btn:[FX] button of that track. This opens the track's FX chain.
3. Click on the Helgobox FX instance.
You will see the xref:plug-in/user-interface.adoc[plug-in window] again.
@@ -0,0 +1,9 @@
= User interface
The plug-in's native user interface features a plain and simple design.
It mainly hosts link:https://www.helgoboss.org/projects/realearn[ReaLearn], the controller integration tool of Helgobox.
include::partial$realearn-specific-ui-elements.adoc[]
.Plug-in window
image::screenshots/plugin-window.png[]
@@ -0,0 +1,58 @@
= Menu bar
include::partial$realearn-specific-ui-elements.adoc[]
== Menu button
This opens the main menu of Helgobox/ReaLearn.
The same menu opens when you right-click an empty area.
It provides the following general entries.
[[open-pot-browser]] Open Pot Browser::
This will open Pot Browser.
See xref:products.adoc#pot-browser[] for details.
[[show-app]] Show App::
Shows the xref:helgobox::app.adoc[] associated with this xref:helgobox::key-concepts.adoc#instance[].
[[close-app]] Close App::
Closes the xref:helgobox::app.adoc[] associated with this xref:helgobox::key-concepts.adoc#instance[].
[[server]] Server::
Helgobox features a built-in server which allows the xref:app.adoc[] (and the old ReaLearn Companion App) to connect to Helgobox.
The server runs globally, not per instance!
[[enable-and-start-server]] Enable and start!::: This starts the server and makes sure it will automatically be started next time you use Helgobox.
Disable and stop!::: This stops the server and makes sure it will not be started next time you use Helgobox.
Add firewall rule::: Attempts to add a firewall rule for making the server accessible from other devices or displays instructions on how to do it.
Open app folder::: Opens the folder which contains the xref:app.adoc[] (in case you want to run it in xref:app.adoc#app-remote-mode[]).
[[export-to-clipboard]]
== Export to clipboard button
Pressing the export button allows you to copy Helgobox settings to the clipboard so you can import them in another instance or edit them in a link:https://en.wikipedia.org/wiki/Text_editor[text editor].
--
The following list only describes the general-purpose menu entries. For the rest, see:
* xref:realearn::user-interface/main-panel/menu-bar.adoc#export-to-clipboard-button[ReaLearn entries]
* xref:playtime::user-interface/menus/export-to-clipboard-menu.adoc[Playtime entries]
--
Export instance as JSON::
Copies a _complete_ dump of this xref:key-concepts.adoc#instance[] to the clipboard in JSON format.
[[import-from-clipboard]]
== Import from clipboard button
Pressing the import button does the opposite: It restores whatever Helgobox dump is currently in the clipboard.
It supports JSON or Luau.
[[help]]
== Help button (?)
Provides links to the reference and other documentation.
@@ -0,0 +1,63 @@
= Welcome dialog
This dialog appears once after installing Helgobox and whenever you start the action xref:reaper-actions.adoc#show-welcome-screen[].
image::helgobox::screenshots/welcome-dialog.png[width=500]
== Checkbox "Add Playtime button to main toolbar"
Lets you enable or disable a button in the main toolbar that starts xref:playtime::introduction.adoc[Playtime].
== Error checkboxes
Like any other complex piece of software, Helgobox might have link:https://en.wikipedia.org/wiki/Software_bug[bugs]. There are roughly two types of bugs: _Subtle_ bugs and _detectable_ bugs. Subtle bugs are very hard to investigate. Detectable bugs, however, are "great" because they contain an error message and give me (the developer) a clue of what went wrong. This clue is crucial because I need it to fix the bug.
The error checkboxes let you decide what Helgobox does if it detects a _detectable_ bug. Let's say the bug occurs. Here's what happens, depending on your configuration:
[cols="1,1,4"]
|===
|Send errors |Show errors | Effect
|Off
|Off
|
A small btn:[ERR] notification will show up in the REAPER title bar (easy to miss!). When you click it, you will see only very basic information about the error.
|Off
|On
|
A console window will appear with detailed information about the error and a plea to send this information to the developer manually.
|On
|Off
|
If you are online, Helgobox will send detailed information about the error to the developer (using the third-party error tracking service https://sentry.io[Sentry], see our https://www.helgoboss.org/privacy-statement[privacy statement]). In addition, a small btn:[ERR] notification will show up in the REAPER title bar. Clicking it will reveal further instructions.
If you are offline, a console window will appear with detailed information about the error and a plea to send this information to the developer manually.
|On
|On
|
If you are online, Helgobox will send detailed information about the error to the developer and show a console window with further instructions.
If you are offline, a console window will appear with detailed information about the error and a plea to send this information to the developer manually.
|===
.Recommendation
[TIP]
====
I recommend enabling both checkboxes!
Sending the error automatically makes sure that I learn about the error as soon as possible, even without your manual notification (I know that you are busy with other things than reporting errors icon:smile-o[]). It also means that the error message shown in the console gets much smaller, as Helgobox then only shows an error ID instead of the full info.
Showing the error in the console in addition makes sure that you don't miss that something went wrong and offers you ways how to deal with the situation. In many cases, it helps if I get further information from you, such as instructions how to reproduce the error.
====
IMPORTANT: Unless you have a live situation (in which case it might make sense to ignore errors), please tick at least one of the checkboxes. I can't fix bugs if I don't know about them! Thanks.
== Checkbox "Notify about updates"
By default, Helgobox checks on startup for available updates. If a more recent version is available, you will see a notification somewhere in the xref:helgobox::plug-in/user-interface.adoc[plug-in window] and the xref:app/user-interface.adoc[app window].
If you don't want ReaLearn to check for updates, you can disable it here.
@@ -0,0 +1,39 @@
= Contained products
Helgobox provides the framework for the following products.
[[realearn]]
== ReaLearn
link:https://www.helgoboss.org/projects/realearn[ReaLearn] is a versatile controller integration tool for REAPER.
It lies at the very core of Helgobox, as controller integration is a key aspect of all the other products it contains.
xref:realearn::introduction.adoc[→ Read more about ReaLearn]
[[playtime]]
== Playtime
link:https://www.helgoboss.org/projects/playtime[Playtime] is a modern session view / clip launcher for REAPER, built straight into Helgobox.
Each xref:key-concepts.adoc#instance[Helgobox Instance] may contain one xref:playtime::key-concepts.adoc#matrix[] (by default not loaded).
xref:playtime::introduction.adoc[→ Read more about Playtime]
[[pot-browser]]
== Pot Browser
Pot Browser is an experimental modern preset browser built straight into Helgobox.
It's just a prototype so far.
It will probably look quite different in the future.
You can open it via menu action xref:plug-in/user-interface/menu-bar.adoc#open-pot-browser[].
It's recommended to use Pot Browser from a ReaLearn instance on the monitoring FX chain, that way you have the browser accessible from any project.
TIP: Add a toolbar button which triggers the REAPER action "ReaLearn: Open first Pot Browser" to get quick and convenient access to the browser.
Remarks:
- Pot Browser is in an experimental stage, it doesn't save any of your settings!
- Each Helgobox instance can have one _Pot Unit_ (by default not loaded).
Each Pot Unit has its own filter and preset state.
When you open the Pot Browser from an instance, it connects to the Pot Unit of that instance.
- ReaLearn's "Pot" targets such as xref:realearn::targets/pot/browse-presets.adoc[] can be used to control the Pot Unit from any controller.
@@ -0,0 +1,23 @@
= REAPER actions
== General actions
Helgobox provides a few global REAPER actions.
You can find those actions directly in the menu menu:Extensions[Helgobox].
Alternatively, search for "helgobox" in REAPER's action list (menu:Actions[Show action list...]).
[[show-welcome-screen]] Helgobox/General: Show welcome screen::
Shows the xref:plug-in/user-interface/welcome-dialog.adoc[] that was displayed after the first installation of Helgobox.
[[toggle-app-focus]] Helgobox/General: Toggle app focus::
Switches focus between REAPER and the xref:app.adoc[].
+
The default shortcut is kbd:[Shift+Cmd/Ctrl+H].
== Product-specific actions
The products contained in Helgobox provide additional actions:
- xref:realearn::reaper-actions.adoc[ReaLearn actions]
- xref:playtime::reaper-actions.adoc[Playtime actions]
@@ -0,0 +1,2 @@
A complement to the xref:plug-in.adoc[] which provides a modern user interface.
It runs embedded in REAPER or as a separate program that connects to REAPER. Mobile versions for iOS and Android are planned.
@@ -0,0 +1,2 @@
Fine adjustments::
Hold the kbd:[Cmd/Ctrl] key while dragging, scrolling or panning in order to do fine adjustments.
@@ -0,0 +1,4 @@
icon:mouse-pointer[] Mouse dragging::
Click and hold the left mouse button, then drag the mouse up or down to increase or decrease the value.
Release the button when finished.
Most elements update the value in real-time as you drag, while others apply the change only after you release the mouse button.
@@ -0,0 +1,3 @@
↕ Mouse wheel scrolling::
Move the mouse wheel up or down to increase or decrease the value. footnote:wheel-direction[Depending on your operating system settings, the mouse wheel directions might be reversed.]
The new value will be applied immediately.
@@ -0,0 +1,2 @@
Reset to default::
Double-click the element to restore the default value.
@@ -0,0 +1,3 @@
icon:keyboard-o[] Enter text::
Right-click the element and enter the value via keyboard.
Press kbd:[Enter] or click somewhere else to apply the value.
@@ -0,0 +1,2 @@
icon:hand-peace-o[] Touchpad panning::
If you have a touchpad, place the cursor over the element and slide up or down with two fingers to increase or decrease the value.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[area-nav-bar-0,Navigation bar]]]
ifndef::pdf-theme[[[area-nav-bar-0,Navigation bar image:helgobox::generated/screenshots/elements/area/nav-bar-0.png[width=50, pdfwidth=8mm]]]]
== Navigation bar
image::helgobox::generated/screenshots/elements/area/nav-bar-0.png[Navigation bar, role="related thumb right", float=right]
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[area-window-title-bar-0,Title bar]]]
ifndef::pdf-theme[[[area-window-title-bar-0,Title bar image:helgobox::generated/screenshots/elements/area/window-title-bar-0.png[width=50, pdfwidth=8mm]]]]
== Title bar
image::helgobox::generated/screenshots/elements/area/window-title-bar-0.png[Title bar, role="related thumb right", float=right]
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-enable-disable-global-control,Enable/disable global control]]]
ifndef::pdf-theme[[[navbar-enable-disable-global-control,Enable/disable global control image:helgobox::generated/screenshots/elements/navbar/enable-disable-global-control.png[width=50, pdfwidth=8mm]]]]
== Enable/disable global control
image::helgobox::generated/screenshots/elements/navbar/enable-disable-global-control.png[Enable/disable global control, role="related thumb right", float=right]
Enables or disables the usage of global controllers for this Helgobox instance.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-home,Home]]]
ifndef::pdf-theme[[[navbar-home,Home image:helgobox::generated/screenshots/elements/navbar/home.png[width=50, pdfwidth=8mm]]]]
== Home
image::helgobox::generated/screenshots/elements/navbar/home.png[Home, role="related thumb right", float=right]
Shows the Helgobox welcome page.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-pick-instance,Pick another instance]]]
ifndef::pdf-theme[[[navbar-pick-instance,Pick another instance image:helgobox::generated/screenshots/elements/navbar/pick-instance.png[width=50, pdfwidth=8mm]]]]
== Pick another instance
image::helgobox::generated/screenshots/elements/navbar/pick-instance.png[Pick another instance, role="related thumb right", float=right]
Lets you pick another Helgobox instance.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-playtime,Playtime]]]
ifndef::pdf-theme[[[navbar-playtime,Playtime image:helgobox::generated/screenshots/elements/navbar/playtime.png[width=50, pdfwidth=8mm]]]]
== Playtime
image::helgobox::generated/screenshots/elements/navbar/playtime.png[Playtime, role="related thumb right", float=right]
Shows the Playtime Matrix associated with this Helgobox instance.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-projection,ReaLearn Projection]]]
ifndef::pdf-theme[[[navbar-projection,ReaLearn Projection image:helgobox::generated/screenshots/elements/navbar/projection.png[width=50, pdfwidth=8mm]]]]
== ReaLearn Projection
image::helgobox::generated/screenshots/elements/navbar/projection.png[ReaLearn Projection, role="related thumb right", float=right]
Shows the ReaLearn Projection page for this Helgobox instance.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[navbar-show-helgobox-plugin,Show Helgobox plug-in]]]
ifndef::pdf-theme[[[navbar-show-helgobox-plugin,Show Helgobox plug-in image:helgobox::generated/screenshots/elements/navbar/show-helgobox-plugin.png[width=50, pdfwidth=8mm]]]]
== Show Helgobox plug-in
image::helgobox::generated/screenshots/elements/navbar/show-helgobox-plugin.png[Show Helgobox plug-in, role="related thumb right", float=right]
Opens the Helgobox plug-in which is controlled by this app.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[settings-color-scheme,Color scheme]]]
ifndef::pdf-theme[[[settings-color-scheme,Color scheme]]]
=== Color scheme
image::helgobox::generated/screenshots/elements/settings/color-scheme.png[Color scheme]
Choose the prominent color for the user interface.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[settings-contrast,Contrast]]]
ifndef::pdf-theme[[[settings-contrast,Contrast]]]
=== Contrast
image::helgobox::generated/screenshots/elements/settings/contrast.png[Contrast]
Choose between multiple color variations that influence the perceived contrast of the app's appearance.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[settings-custom-color-rendering,Custom color rendering]]]
ifndef::pdf-theme[[[settings-custom-color-rendering,Custom color rendering]]]
=== Custom color rendering
image::helgobox::generated/screenshots/elements/settings/custom-color-rendering.png[Custom color rendering]
Choose how to render user-defined colors, such as for tracks and clips.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[settings-dim-opacity,Dim opacity]]]
ifndef::pdf-theme[[[settings-dim-opacity,Dim opacity image:helgobox::generated/screenshots/elements/settings/dim-opacity.png[width=50, pdfwidth=8mm]]]]
=== Dim opacity
image::helgobox::generated/screenshots/elements/settings/dim-opacity.png[Dim opacity, role="related thumb right", float=right]
Adjust how much to dim the Helgobox app window when pressing the dim button.
@@ -0,0 +1,8 @@
ifdef::pdf-theme[[[settings-display-development-status-hints,Display development status hints]]]
ifndef::pdf-theme[[[settings-display-development-status-hints,Display development status hints]]]
=== Display development status hints
image::helgobox::generated/screenshots/elements/settings/display-development-status-hints.png[Display development status hints]
If enabled, the inspector will display even settings that are not available yet and it will show small annotations about the development state of a feature.

Some files were not shown because too many files have changed in this diff Show More