Skip to content

Dynamic Controller

Description

A controller whose value can be dynamically changed. Values can be changed at once or using ramps.

Syntax and Default Values

The dynamic controller can be created using the following Mlys (Max), mlys.lua, or Lisp syntax:

In Modalys for Max, this object is named mlys.dynamic:

    
        ----------begin_max5_patcher----------
        2191.3oc6bssaqaiE8YmuBVM8gyAvwPaRpaEnCBv7AL881h.EaZG0JKYHQ6ykhd9P5S8aa9RFdS1xIz1JITxAEJAPxlRVjq8Ut2bS8G2Lw6gxOyp8P+.5mQSl7G2LYhpIYCSLeeh25zOOOOsVcadyKWulUv8lpuFm8Ytp8Ojlmi1klukU+wlKlsPcoxG9saoAMMVrccVQNiqdbvgFK2xaZ02z5lT97GyJVceEaNWOHig3Y9SQw9xiQf7HV7YzuJ+E+4M2HOL8sBkpzheGUugMOaYFagU3PcDbBBjP.BvpS3n2DfVypqSWwdFfVw3YEKK0rGz+gWkC1vDwJlvVwDbZLAQ9yBDnvfIeEBwXIlL+H8yg+kML8uvya+kVUktHSxTZ0GOrZdYdYk9d8mA.IBGPS7gjP+n3ohlnwXR.NgBPTHMBjMEjfgfv3PbDMvOQbWPqAf4Ihadj3osNb7MtLKOWcy22LdOLFsbSpifSGpO4g+xFztmxc3YmtkW1leI0IsbWEqxUzMbj8aXSU4lxJdVYg9gDzqR9XaR99tQxOxOTYVJoeD7eFiwNGUblRZZGecD7cxP0cB9Nd37NRvuf8IgD7yj62TkcfM0VRG6F+VTfJEtEDS4IB9fj9qACaW+.qx1ncuapMoUoqYbV08rhzGzjU+tiD7YzYwpIT.PnFPcPmcJx6AAy0qm8QiQeuM2zjDGYrx.7.PO0C7UwZEI9HGPumsVcgg5PaspyCm2+VqVm+k5YaJElrtUHysYKGc27GSKJX4HJ5tZVtPnsrBYy0MIrowkkE75rupv.b.Bcv5vYTRBzga.QpIlCIsle9kURpS2wVbuXTJdb2mx4UYOrkqi1ZxdBzDOCTkMSmZZaUZlhLCM3PLlEF.Uv9mjDp+qhN40bwFZjdLf0Vlzbm9mGQZwirZwh1q7HBfGRdD4ExitGNAWBFVtDtEWx2FWB2qbIveP0jvuTtD9DbI+gkKYU+A5UNSrhwjnYOTne4KvKkuP7d8j+54kaXeqg3I8CtNkmMuM8nR32yfqaUTTEccO.ayEdIoG4bScVOa4f.0DNSz4+gPdkyc1oPDntAhDh+6VHF5FHh0op68HDCwtAhZ6BNBgmvRH+wpsVr3ADO23zQiApdVb3jNEhSuiNpa.mH5.E3nz9EbmJM4+3+FUy3l.VKWhTYM+eAnOTySq30nkUkqQekUU9ceDwKQIInTNprX99XeyyJXyK2piJAawharaRVQBknxRg9Djnzdd0RxmJ.9ZKAvCBTaygdjaBgOVaHnAXDXLD9wP3uRYZWKv6K+2lDefiRZk1lmYskBoiB7iB78r.+Yb+IcfkVgXE6X4hIvMEUWhdjUwPehgdTDZzO7KEbg.5G14i1AncXgeP3nuga8st5UDSbzROSUyfkZ7ZDh6Euhoa1j+kFBjwqHFkn9mpMWfBEe9VYCwmz9Al5HOlD8DB80oeHJYz.xnAjqmAj5z0LDa4Ro7oEgdGUyLIZUbB.GRziyqwDaS+kHTwCrArPGMaf3PMvzwCSBF0lG0luhZyhngEA59gHgirjOhJ2wpPfun441zAhbjxsVqlDoTEfv9oBxz5yJfIfjM3D6HGzXpFNJc43wHZG0neGnQqbj8wml+p1h+INZR4lRoIVujllxQoezlOk2YhqpFtvfVXYLV8QU42Qwp+KE+u+5uQ7Lw7uWlUUymh3OxJzyd8YwwijQwuSbKf9DFsal0v0IVrL3pJtSufSDs1D1WYYPFBeOGtNHhHWlH6aIhSV87CtwbA1jkdioOmGZ9wR3zo1UDhZtttNPuRkMtKFpNrrwc6v4eDgl66FsZRSn4INHzb1WWjN+a1VN0D2rhvPLcljyRSvpyDxLyQWtpoppioddU1FaTdH1ygU8BQGtQ3KJyAcrpWTRv2ttbgV8eAaUEisuJiVuMmm0hdKFjhAWVsQd1aQ4VYcN+5K9EwXhKdVVnfQNpppuH0EqrnqIwximl3595o944iBPjY1HGNZoovlZg2TwnlRNXz+0n+qqYnqAyL4g5DogB.23HCappBytInGCbEjXxVYRBXGoHiCZAkfnQ83Q83qtdLY1Yx9D3nYihol5jyu+Uhs5K1QasISY+YvAcTCdTC9ZsylJWjJBm4aB+uTKx6ujXYBtzrsoIsd0Hbdw85rUEo4xMx34+zKNlmiig4MD8xYrHtHSbEYef9QDDNEIYjrEnOkweTUto0VHzNZw1HZKJXvrJazd48OwSvHwBdBcU5GB2WV2ucC9ckmYAONpRGH5cwajS7ectzSr3KEoqylitStmUTQWRP2c.jG1kAOw0A8HKaARqcBid9j8FAUME7zrwCmXKoXceAgc0N1hhUuGOzzTLE2C4HYOISMVBe1NARQY2myDUr7MjR+ot6PesGudtXBFcmNiD.BePy9oKs09UcwOHNFeBoDx9aPsLMmTJA2uRIl80mYgKI98sTBwpPB1lPht5ATAyMj7XngGKlvSvIXwPaFLQwOoGwzUSNJ5o20IXwPuxh0SuHzrfLg8tY.qLXvtU.gQd0eABKkzPpMlrZvnVmtm7htRAUY6Gy4qK2VMuAJMuwEPGf6BVMOqHsY9h+79M0C5T9Y5ZGIeOzLLcDoCcDPbPOIlgKhdIDgcAjfN.oFN4apmRFRZ2k5nPri5HxkHctBQvkHcgNpivWpibhlTG3QwNnejaYrAwzfbm5z0NxbOOlsXASa59s003tnY4DpILX8zPYRmLTHBGOPHBGNTcDcn5HXnbczEMIxwz2xpEL0zS86+dlZumg9umw16Y7apmg3t6Evw1Lgt3W.bfDEDLTxt.Yf7oB3ACRcQz74bIcjKoa1riU0DcjpODQm9a5XIimp9ZVg9qpLn3Uw1sOIrpEOwKsRDTGWDD11JcHUeNTmOZYFpYUEayLhhBzI5RUjuxvup2jpAhJ.4a9ya9+03Rn5C
        -----------end_max5_patcher-----------
    

😉 Click the button above to copy/paste a full example to Max (New From Clipboard) ☝️  

The value parameter can be used for a single value or for a multiple dimension controller (i.e a list of values separated by spaces).
👍 If you change the dimension parameter, the value list will change in size accordingly. Likewise, if you change the size of the value list, the dimension parameter will adapt.
The period parameter is hidden: period = -1 (auto update).

c1 = modalys.create_controller{ kind="dynamic", name="Ctrl1"} --> dim = 1
c2 = modalys.create_controller{ kind="dynamic", name="Ctrl2",
                                value={0.1,1.4,1.3e-8}, --> dim = 3
                                subcontroller="yes" }

If dimension is specified, with no value, a zeroed controller of that dimension is created. Otherwise the dimension is automatic, based on the value's dimension.
The period parameter is optional and set to -1 (auto update) by default (no need to change it).
The subcontroller parameter is optional; if set, the lua controller is made dependent upon this newly created controller (which becomes a subcontroller).
NB: If kind is not specified, the controller is 'dynamic' by default!

(make-controller 'dynamic
                  dimension
                  period
                  (list v1 v2 ... )
                  name)

The dimension and period parameters are mandatory in Lisp (period should always be -1 i.e. automatic).
The number of initial values should match the number of dimensions.
When using the dynamic controller to receive Max messages, the name should be given as a string, i.e in quotes: "button1", etc.

Parameters and Default Values

The 'dynamic controller takes four arguments:

  • dimension: number of dimensions of the output controller
  • period: sampling period (seconds).
  • value: a list of initial (default) values for the controller.
  • name: the name (in quotes) that is used for Max messenging.

Changing Values Over Time

The value(s) of a dynamic controller can be changed with a variety of messages:
When dimension is > 1, the syntax is a bit different:

In Lua you can use the same external Max messages to alter the values.
Internally you can use these lua functions:

set_value{ctrl=c1,value=3} -- set to 3 at once
set_value{ctrl=c1,value=5,time=1} -- set to 3 over 1 sec

-- If dimension > 1 we have:
set_value(ctrl=c2,value={3,4,5}) -- set to {3,4,5} at once
set_value(ctrl=c2,value={7,8,9},time=10) -- set to {7,8,9} over 10 sec
set_value(ctrl=c2,value=99,rank=1) -- value of rank #1 (zero-based) set to 99

-- Envelopes are also available in Lua:
-- p.value is expected to be a suite of time/values: t1,v11,v12...v1n,...,tm,vi1,vi2,...vmn
apply_envelope{ctrl=c1,value={0,2, 1,-3, 2,0}}
-- or, with a better visibility, with times and values separated:
apply_envelope{ctrl=c1,value={2,-3,0},time={0,1,2}}

-- For dimension > 1:
apply_envelope{ctrl=c2,value={2,9,9,9, 4,0,0,0, 6,-2,-3,-4, 8,0,0,0}}
-- same effect but with times and values separated:
apply_envelope{ctrl=c2,value={9,9,9, 0,0,0, -2,-3,-4, 0,0,0},time={2,4,6,8}}

There are two ways a dynamic controller may be used. The "historical" way, from the days before computers were fast enough to compute samples in real-time, is to instantiate the controller and then send messages to it, using (send-message ...) in-between (run) statements. First the controller is defined, with a message name as a final argument:

(setq my-ctl (make-controller 'dynamic 1 0 '(0) "ctrl1"))
Using the message name as a final argument allows the controller to be typed directly into other Modalys functions, without needing to use (setq ... ) to create a reference to it.
The general syntax of the (send-message) function is:
(send-message "<controller name>"
              (list v1 v2 ... time))
The following series of runtime statements will create the value changes shown in the graph above.

(run 0.25) ; run for 250 ms, controller is at default value
(send-message "ctrl1" 1 0.5) ; moves to 1 over 500 ms.
(run 0.25) ; run for 250 ms, beginsto ramp upward to destination value
(send-message "ctrl1" -1 0.5) ; stop at current value, initiate new ramp.
(run 0.5) ; run for 500 ms, ramp downward to new destination value
(send-message "ctrl1" 1) ; jump to value = 1 at once (no ramp time)
(run 0.5) ; run for 500 ms, remain at the value 1
(send-message "ctrl1" -1 0.5) ; ramp to -1 over 500 ms.
(run 0.5)
This "runtime" functionality is still useful when testing out "instruments" inside the Lisp environment.

Alternatively the (set-breakpoint) function can be used to set the ramp. The general syntax is:

(set-breakpoint controller
         (list time v1 v2 ... ))
⚠️ Two syntaxical differences here: 1) the controller is passed as a reference, not as as "name". 2) the time parameter preceeds the values.

For real-time context, please use Modalys for Max.

Getting Values

To query the value of a controller, you need to send a message to the object modalys~:

getinfo value Ctrl1 : one-dimensional case
getinfo value Ctrl2 : multi-dimensional case
getinfo value Ctrl2 1 : rank specified (⚠️ the rank is zero-based!)

The result will be then output from the right outlet of modalys~:

getinfo value Ctrl1 0.15
getinfo value Ctrl2 1. 2. 3.
getinfo value Ctrl2[1] 2.

-- setting the value at once:
local ctrl1 = create_controller{kind="dynamic",value=4.7,name="Ctrl1"}
local ctrl2 = create_controller{kind="dynamic",value={0.7,-2,3.1,-4.9},name="Ctrl2"}
-- getting the value:
local x = get_value(ctrl1) -- x = 4.7
local y = get_value(ctrl2) -- y = {0.7,-2,3.1,-4.9}
local y1 = get_value(ctrl2,1) -- y1 = -2 ⚠️ the rank is zero-based!

The (get-info 'value ... ) function requires the following two arguments to get information about an access:

  • controller_reference: the controller whose value we want to query.
  • index: desired value index (should be 0 for a 1-dimensional controller)

An example which gets the value from a one-dimensional controller:

(get-info 'value my-controller 0)


★     ★