Source Code | Tickets | Trello | Twitter | Patreon | © Michael DeHaan, 2020

Evaluators


Evaluators

Evaluators are expressions that are valid for any value in a Slot. They can be used to achieve controllable per-step randomness, pull values for a Data Pools or pull notes from one track into another.

Use of evaluators allows Warp to produce expressive, highly evolving compositions full of emergent behavior, operating off a very small amount of data, and often zero custom programming. As the UI in Warp is built, evaluators will be fully exposed to the user interface, and not remain exclusively a programming feature.



Probability 

In the example below, the 4th note has a 40% chance of being silenced:

api.patterns.add(name='foo', slots=[
    Slot(degree=1),
    Slot(degree=2),
    Slot(degree=3),
    Slot(degree=4, rest=Probability(0.4,True,False)
])
In the example below, there is a 40% chance of an octave shift:

api.patterns.add(name='foo', slots=[
    Slot(degree=1),
    Slot(degree=2),
    Slot(degree=3),
    Slot(degree=4, octave_shift=Probability(0.4,-2,0)
])

RandomChoice 

In the example below, the note is chosen from a limited set of possible notes:

api.patterns.add(name='foo', slots=[
    Slot(degree=RandomChoice(1,2,4,7),
    Slot(degree=4),
    Slot(degree=5)
])

RandomRange 

In the example below, the velocity is selected within a narrow range, implementing humanization

api.patterns.add(name='foo', slots=[
    Slot(degree=1, velocity=RandomRange(80,90),
    Slot(degree=2, velocity=RandomRange(80,95),
    Slot(degree=3, velocity=RandomRange(85,95),
])

LoadVariable 

Variables are global and can be shared between tracks. As a result, one pattern, perhaps even playing on a muted track, can influence another. Here is a trivial self-contained example:


api.patterns.add(name='foo', slots=[
    Slot(degree=1, variables=dict(a=1, b=2)),
    Slot(degree=2),
    Slot(degree=LoadVariable('a')),
])

TrackGrab 

Track Grab listens to what note is playing on another track and replaces the current note with that value. See this hocket example.


api.patterns.add(name='foo', slots=[
    Slot(track_grab='conductor')
])

DataGrab 

Somewhat like a TrackGrab, a Data Grab pulls the next value from a Data Pool. This could be a fun way to interlace one melody into another. J.S. Bach, here we come!


api.patterns.add(name='foo', slots=[
    Slot(degree=DataGrab('some_pool'),
    Slot(degree=4),
    Slot(degree=5),
    Slot(degree=DataGrab('some_pool'),
])

Negate 

If you need to negate the value from a DataGrab you can't use the minus sign because a DataGrab is some kind of magical timey-whimey object. You need to use Negate


api.transforms.add(name='octave_shifter', slots=[
    Slot(octave_shift=1),
    Slot(octave_shift=Negate(DataGrab('mcelligots_pool')),
    Slot(octave_shift=1),
])

This is a preview of this next thing...


Nesting Evaluators 

Technically you can nest Evaluators at infinite level. If you need to randomly decide to use a DataGrab or a constant, for example:


api.transforms.add(name='maximum_chaos', slots=[
    Slot(octave_shift=1),
    Slot(octave_shift=Probability(0.5, DataGrab('the_deep_end'), 2),
    Slot(octave_shift=1),
])

Any parameter to any evaluator can be subject to nesting.


Suggestions & Tips 


In Context 

Reading the following API examples is recommended for understanding this section:

Next Steps 

This is already pretty far into the Warp feature set. Be sure to read about Data Pools which are used with DataGrab.