» sp.Dynamic Plugins
This site relies heavily on Javascript. You should enable it if you want the full experience. Learn more.

sp.Dynamic Plugins

English | Italian | French

Introducción

¿Qué?

Entonces, ¿Cuál es la nueva característica que permite escribir nodos?
Una manera de verlo sería que acabamos de añadir soporte c# a tu entorno de desarrollo favvvvorito. Porque aunque no te veas como desarrollador, ya estás programando: por ahora lo has hecho visualmente. Ya estás construyendo tus propios nodos cuando patcheas subpatches o módulos.
Así que a partir de ahora sólo hay más posibilidades sobre cómo crear nuevos nodos: patchear visualmente o escribiendo textualmente.
Para no abusar de los términos visualmente, textualmente, nodo vvvv o nodo c# , estamos revisando los términos de 'patch' y 'plugin'. Un plugin simplemente es un nodo escrito textualmente.

Lo nuevo es la manera en que puedes escribir plugins: dinámicamente en vvvv, lo que debería facilitar la manera de entrar en programación c#.

¿Por qué?

Bien ¿Por qué querrías usar c#?
En primer lugar están las tareas de programación, que son más fáciles, más rápidas o con mayor rendimiento hechas en c#, ya que cada lenguaje de programación tiene sus puntos fuertes y sus inconvenientes. Además todavía hay cosas que no puedes hacer con patches (como el uso de algunas poderosas librerías NET llamando directamente a sus métodos)

Comenzamos

Para patchear un nuevo nodo usa CTRL-SHIFT-P para colocar un patch vacío virgen dentro de tu patch actual, empieza a colocar algunos ioboxes para inputs y outputs, nombrarlos y conectalos a los nodos que hacen el trabajo real dentro de tu subpatch / module.

Para escribir el nuevo nodo no hay ningun atajo de teclado que inicie el plugin c# vacío. Se nos ocurrió que podría ser más fácil comenzar a partir de templates muy simples que ya cuentan con un input y un output.

¿Cómo?

En vez de crear un archivo de texto vacío, comienza seleccionando alguna template como Template (Value). Cuando acabes de crear esa template verás que funciona (multiplica el input por 2). Click derecho muestra el interior (igual que click derecho en en un subpatch muestra el patch). Ten en cuenta que no se puede modificar una template. Así que lo que hay que hacer es clonarla. Para clonar una haz doble clic izquierdo en el patch lo mismo que haces para crear un nodo normalmente, escribe "tem" y finalmente selecciona la template que se va a clonar mientras presionas CTRL. Especifica el directorio donde se clonará como se explica al final de la sección.
En el diálogo elige un nuevo nombre.
Puedes elegir en cualquier momento un nuevo nombre, categoría o versión clonando tu propio nodo. Esta es la mejor forma de renombrarlo de una manera consistente: se crean un montón de entidades que habría que renombrar (archivos, carpetas, clases e infos), de este modo no tienes que preocuparte por poner nombres estúpidos, ya que tienes una herramienta de un solo clic para arreglarlo ...

Por último, una pequeña idea: piensa en términos de value, color o string; imagina un pequeño nodo que hace simples operaciones lógicas aceptando hasta 5 nodos para patchear..

Conecta ioboxes a los input y output: verás cómo los outputs cambian instantáneamente en cuanto cambies y guardes el archivo .cs (CTRL-S desde el editor de código). Importante: Guarda tu patch de prueba dentro del directorio de proyecto en "vvvv \ plugins \ YourDynamicPlugin" y el nombre "YourDynamicPlugin (Categoría Version) help.v4p".

El Editor

regions

El editor de código soporta el plegado de código. Esto significa que puedes ocultar / mostrar ciertas regiones de código haciendo clic en los botones - / + en la parte izquierda de tu código.
Las regions están marcadas como

#region SOMEREGION
#endregion SOMEREGION

donde SOMEREGION representa cualquier nombre de región (que puede incluir espacios).
La plantilla tiene las regiones "usings", "PluginInfo" y "fields & pins".

colores

El editor de código usa automáticamente colores y estilos que hacen el código más leíble. En general se puede decir que el tipo de token decide qué color o estilo se utiliza.
Después de algún tiempo te beneficiarás de este feedback instantáneo que te muestra si el código está bien formado.

Entendiendo Template (Value)

La primera cosa de c# que tienes que saber es qué es namespaces o espacio de nombres. Namespaces es la forma de estructurar la enorme colección de librerías incluídas en .NET y las adicionales que vienen con vvvv. No necesitas conocer todas esas librerías, te vale con comprender el concepto.
Se puede comparar con los animales y cómo se clasifican. No necesitas conocer todos los animales para captar la idea... bio classification

También puedes verlo como una estructura jerárquica general

Vehicle.Car.VW.Polo

que va desde lo inespecífico a lo específico donde los puntos marcan los subdirectorios.

using

A todas las entidades en . NET se puede llegar mediante una ruta global, la cual es una combinación del namespace en el que se define la entidad y el nombre de la entidad.

VVVV.PluginInterfaces.V2.ISpread<bool>

VVVV.PluginInterfaces.V2 es el namespace donde ISpread<bool> (la spread de booleanos) es definida.

La declaraciones using se utilizan para poder acortar el código diciendo solo ISpread<bool>. Para que funcione es necesario declarar el namespace (VVVV.PluginInterfaces.V2) una vez al principio del código.
Por ahora solo se han declarado unos pocos namespaces standard de los cuales 2 son standard .NET namespaces:

using System;
using System.ComponentModel.Composition;

y 5 son vvvv namespaces

using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;
using VVVV.Utils.VColor;
using VVVV.Utils.VMath;
using VVVV.Core.Logging;

aquí tienes algo más para tus futuros experimentos: namespaces.

namespace

También tu nuevo nodo es una entidad definida en el namespace. Como nodo que es resulta fantástico conservar el nombre del namespace "VVVV.Nodes".

namespace VVVV.Nodes
{
}
bloques de código

Puedes seguir adelante aunque ignores lo que hace referencia al namespace.

Solo ten en cuenta que las llaves {} marcan un bloque de código, y que el resto del archivo se encuentra dentro del bloque de

código del namespace VVVV.Nodes .

Los bloques de código son necesarios para estructurar el código y es bastante común encontrarlos anidados. Se percibe como

buen estilo el uso de sangrías por medio de TAB ya que hacen la estructura más visible para los humanos (que generalmente no

miran las llaves {}).

PluginInfo

[PluginInfo(Name = "Template",
        Category = "Value",
        Help = "Basic template with one value in/out",
        Tags = "")]

La plugin info es una parte en la declaración de tu nodo. Establece que la clase que se define a continuación es un nodo.

Solo las clases marcadas bajo la firma PluginInfo podrán aparecer en la lista del busca-nodos (node browser).

Name y Category son obligatorios, el resto es opcional.

Más en PluginInfo Attributes

clases

Un nodo es una clase, y una clase es un bloque muy básico de construcción en c#. Hace unas llaves alrededor de la data y el

código. Son necesarias para escribir nodos.

Compara esto con un patch:
Las entradas Inlets y salidas outlets (llamadas ioboxes) en los modules corresponden a la parte de data, y los nodos

que hay dentro corresponden a la parte de código que dice lo que se va a hacer.

campos y pins

La parte de data: sobre todo los inputs y outputs de tu nodo.

[Input("Input", DefaultValue = 1.0)]
ISpread<double> FInput;

Al igual que en la declaración del nodo, otra vez tenemos

  • la notación c# en bruto (en este caso un campo/field de data)
  • y encima una firma que le dice a vvvv que esa data debe aparecer como pin.

Note that fields without pin signature can make perfect sense. It is then a private piece of data, which you need for your calculations but don't want to show the user of your node as a pin.
When you change your mind and want to make something configurable by the user you would place an inputpin signature above and will get a pin to receive data from the user.
Or you might want to show some precalculations to the user. For this you would add an output pin signature above the data field and the node will get another output pin.

[Output("Step 2 in big Calculation")]
You can again compare the adding of a pin signature with naming an iobox in a module, which also results in a new pin in the patchs' node representation. In both cases the patch or the c# node are already working and adding the signature or naming the iobox only result in adding the pin.

For a pin signature it is mandatory to specify if it should be an input or an output and the Name. All further attributes are optional.

How to configure pins: Pin Attributes

Pin Type: ISpread<T>
ISpread<double> FInput;
ISpread<double> FOutput;

Above you see the raw c# declarations of input and output in the Template.
To the left there is the type of the pin data (ISpread<double>), on the right the internal c# name (FInput, FOutput), which typically starts with "F" for "field".
The declaration follows the scheme FieldType FieldName;

Note that in our example the type of data for input and output is the same: just a spread of doubles (ISpread<double>). A double is a floating point number (informatic term), which is a real number (mathematic term), which is just a number (for all). See other templates how to work with other spreads (like a spread of strings).
In general we say that all inputs and outputs are of type ISpread<T> where T stands for the element type which can be:

float, double, bool, int, ..
resulting in a value pin
string
string pin
RGBAColor
color pin

and so on

Only fields of type ISpread<T> (with any T) can be turned into pins by adding a pin signature.

Other fields
[Import()]
ILogger Flogger;

ILogger is some interface on which you can call the method Log(). A method is something that does something, in this case writing into a Renderer (TTY). So the Flogger can easily be used to write out some debug information.

the Evaluate method

We just learned that a c# method does something.
Well, didn't we also want to get our node to do something?

public void Evaluate(int SpreadMax)
{
}

declares a new method.

You can declare several methods in your class.
The Evaluate method however again is a special vvvv thing. It is called when the output values are needed.
They are needed when

  • the evaluation of the whole patch system requires the output of your node to be computed or
  • you hover with mouse over an output (resulting in a tooltip with the current value) or
  • if an IOBox is attached and therefore the output values are needed to update the GUI.

You can see that your node is evaluating only when the output is needed by following these steps:

  • create a Renderer (TTY)
  • ensure that nothing is linked to the outputs of you node
  • hover with the mouse over an output

You should now see that the node is only doing what it is told to, when the output is needed: the output is needed because of the tooltip, therefore Evaluate is called, which also results in prompting messages to the Renderer (TTY) (explained below). Hovering away stops the logging and therefore shows that Evaluate is not called anylonger.

If you want to ensure that the node is just called each frame (independently of if any ouput value is needed) you would need to add an attribute to the PluginInfo:

[PluginInfo(...,
        AutoEvaluate = true)]
Again you can compare the Evaluate method with the nodes within a module: both work on the input data and are responsible for feeding the outputs.

So everything that you want your node to do comes into the evaluate method between those brackets.

FOutput.SliceCount = SpreadMax;

says that the size of the output spread should be equal to the biggest spread of all inputs, and since for now we only have one input, output and input spreads will have the same slicecount.

for (int i = 0; i < SpreadMax; i++)
    FOutput[i] = FInput[i] * 2;

For each slice calculate the output by multiplying the input slice by 2.
Note that you could do more in the for loop. For that however you would again need a code block:

for (int i = 0; i < SpreadMax; i++)
{
    someCommand;
    otherCommand;
}

Flogger.Log(LogType.Debug, "Logging to Renderer (TTY)");

writes some debugging message to the console.
Typically you would use the logging feature to test if some code has been executed (e.g. inside an if statement).

How to move on

Dynamic Plugin Tutorials: Things you can try out to get into c# programming
Learn C#

anonymous user login

Shoutbox

~8d ago

joreg: Postponed: Next vvvv beginner course starting April 29: https://thenodeinstitute.org/courses/vvvv-beginner-class-summer-2024/

~1mth ago

~1mth ago

joreg: The Winter Season of vvvv workshops is now over but all recordings are still available for purchase: https://thenodeinstitute.org/ws23-vvvv-intermediates/

~2mth ago

schlonzo: Love the new drag and drop functionality for links in latest previews!

~2mth ago

joreg: Workshop on 29 02: Create Sequencers and Precise Clock Based Tools. Signup here: https://thenodeinstitute.org/courses/ws23-vvvv-08-create-sequencers-and-precise-clock-based-tools-in-vvvv-gamma/