concerning c# and plugin writing, there is another issue i’m struggling with
i am trying to decode osc-messages in a dynamic plugin. the message is received through a string in the FInput inlet. basically this code should do what the OSCDecoder (Network) should do. but no luck so far, since my vvvv is crashing, when i’m using the code below.
i think i’m doing something wrong with inizializing the OSC field.
Am I initializing the OSCMessage class and its fields (FOSC in this case) correctly (the lines where i write: Import()… OSCMessage FOSC) ?
Am i using the correct class to decode the osc-message, which comes as a string (FInput). I mean is the approach (FOSC.Append( and the following 2 lines correct?
using System;
using System.ComponentModel.Composition;
using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;
using VVVV.Utils.VColor;
using VVVV.Utils.VMath;
using VVVV.Utils.OSC;
using VVVV.Core.Logging;
namespace VVVV.Nodes
{
[PluginInfo(Name = “test_oscccccTemplate”, Category = “String”, Help = “Basic template with one string in/out”, Tags = “”)](PluginInfo(Name = “test_oscccccTemplate”, Category = “String”, Help = “Basic template with one string in/out”, Tags = “”))
public class test_oscccccTemplate : IPluginEvaluate
{
[Input("Input", DefaultString = "hello c#")](Input("Input", DefaultString = "hello c#"))
ISpread<string> FInput;
[Output("Output")](Output("Output"))
ISpread<string> FOutput;
[Import()](Import())
OSCMessage FOSC;
//called when data for any output pin is requested
public void Evaluate(int SpreadMax)
{
string test="";
FOutput.SliceCount = SpreadMax;
FOSC.Append(FInput);
FOSC.Address="/ticktack";
test=FOSC.ToString();
FOutput[0](0)=test;
}
}
}
Sorry for all these questions, although i’m going through a c# introduction at the same time, i’m still at the basics of how to use the things… … i’m really looking forward to the plugin-writing-for-beginner-workshop at the node festival. but until then…
please check this source for correct usage of the osc utils. note, this code is not a plugin itself, but only demonstrates the usage of the osc code. hope that helps.
i gave it another shot, but unfortunately without success so far… i tried to implement listening to a port, receiving osc-messages, according to code joreg linked in the post above (though, i didn’t implement processing the osc-message, since i didn’t even manage to initialize the receiver).
either vvvv crashes or i got the following error: “Socketadresse darf nur jeweils einmal verwendet werden”
also, i’m not sure whether the listening-process must happen in a dedicated thread, as in the code above.
i was debuggin with the attached file and i elaborated the following code snippet. but in this state, vvvv crashes after a while, after the mentioned errormessage occurs. i assume there is a fundamental error.
if anybody could give me a hint?
- region usings
using System;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Collections;
using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;
using VVVV.Utils.VMath;
using VVVV.Utils.OSC;
using VVVV.Core.Logging;
using System.Threading;
- endregion usings
namespace VVVV.Nodes
{
#region PluginInfo
[PluginInfo(Name = "test_osccciimakerTemplate", Category = "Value", Help = "Basic template with one value in/out", Tags = "")](PluginInfo(Name = "test_osccciimakerTemplate", Category = "Value", Help = "Basic template with one value in/out", Tags = ""))
#endregion PluginInfo
public class test_osccciimakerTemplate : IPluginEvaluate
{
string FOSCAddress ="/ticktack";
bool FListening = false;
[Input("Initialize")](Input("Initialize"))
IDiffSpread<bool> FInitialize;
[Input("DoRead")](Input("DoRead"))
IDiffSpread<bool> FDoRead;
[Output("Output")](Output("Output"))
ISpread<double> FOutput;
[Import()](Import())
ILogger Flogger;
private Thread FThread;
private OSCReceiver FOSCReceiver;
//called when data for any output pin is requested
private void StartListeningOSC()
{
FListening = true;
FThread = new Thread(new ThreadStart(ListenToOSC));
FThread.Start();
// ListenToOSC();
}
private void StopListeningOSC()
{
FListening = false;
if (FOSCReceiver != null)
FOSCReceiver.Close();
FOSCReceiver = null;
}
private void ListenToOSC()
{
OSCPacket packet = FOSCReceiver.Receive();
if (packet!=null)
{
if (packet.IsBundle())
{
ArrayList messages = packet.Values;
for (int i=0; i<messages.Count; i++)
//ProcessOSCMessage[OSCMessage)messages[i](i](https://vvvv.org/documentation/OSCMessage)messages[i](i);
Flogger.Log(LogType.Debug, "Packet is a bundle!");
}
else
//ProcessOSCMessage((OSCMessage)packet);
Flogger.Log(LogType.Debug, "Packet is not a bundle!");
}
else
Flogger.Log(LogType.Debug, "UDP: null packet received!");
}
public void Evaluate(int SpreadMax)
{
if (FInitialize[0](0))
{
Flogger.Log(LogType.Debug, "...");
}
if (FDoRead[0](0))
{
FOSCReceiver = new OSCReceiver(3001);
FOSCReceiver.Connect();
Flogger.Log(LogType.Debug, "listening.. crashing?");
StartListeningOSC();
}
else
{
StopListeningOSC();
FOutput[0](0) = 3.1;
}
}
}
}
you didn’t exactly choose an easy thing to start with… attached is a simple demo.
the important bits are:
in your example you created a new OSCReceiver everytime the DoRead pin was on. thats no good. see how in the sample one receiver is being created in the constructor
threading plus the oscreceiver being bound to a port makes the thing very sensitive. everytime you destroy the plugin (ie. ctrl+s/recompile) you need to make sure the thread is closed and the OSCReceiver closed and nulled. for this you have to implement the IDisposable interface, which is ugly code, but is necessary. i hid it in the constructor/destructor region.
in the ListenToOSC() function you removed the while(FListening) part which is essential for the thread to run in a loop. i put it back in.
note that the demo ignores multiple messages in a #bundle. it will only return the last.
the question remains if you really want to duplicate the UDP->OSCDecoder functionality in your plugin?! i’d argue it would be much easier to use the oscdecoders output as input to your plugin…
you were right, the plugin you posted was really sensitive.
since this solution would imply too many problems, like listening to more than one port, etc. i implemented just the osc-decoding in my plugin, as iactually intended in the first post.
like this, i receive a spread of strings from the upd-node, which i decode (of course the OSCDecode node does the same, but it was important to have it in a plugin for this project)
i post the code snippet, maybee it is helpful for someone else, struggling with the osc-namespace… here the FOSCMessages is the spread of messages coming from the upd-node.
private byte[]() StringToByteArray(string str)
{
return System.Text.Encoding.GetEncoding(1252).GetBytes(str);
}
private void ListenToOSC()
{
if (FListening)
{
for (int x=0; x<FOSCMessages.SliceCount; x++)
{
if (FOSCMessages[x](x).Contains(FOSCAddress[0](0)))
{
OSCPacket packet = OSCPacket.Unpack(StringToByteArray(FOSCMessages[x](x)));
{
if (packet != null)
{
if (packet.IsBundle())
{
ArrayList messages = packet.Values;
for (int i = 0; i < messages.Count; i++)
{
ProcessOSCMessage[OSCMessage)messages[i](i](https://vvvv.org/documentation/OSCMessage)messages[i](i);
//Flogger.Log(LogType.Debug, "packet is bundle");
}
}
else
{
ProcessOSCMessage((OSCMessage)packet);
//Flogger.Log(LogType.Debug, "packet isnt bundle");
}
}
else
Flogger.Log(LogType.Debug, "packet is not okay. either address mismatch or message is fucked up");
}
}
}
}
}
private void ProcessOSCMessage(OSCMessage message)
{
string address = message.Address;
ArrayList args = message.Values;
//FDecodedOSCMessages.Clear();
if (address == FOSCAddress[0](0))
{
FDebug.SliceCount = args.Count;
for (int i = 0; i < args.Count; i++)
FDebug[i](i) = args[i](i).ToString();
}
}
this code should also solve the issue of having multiple messages in a bundle… the code works for me, its still a bit dirty. any hints are very welcome…
the typeTag is a private field, it would only contain some characters. its better to iterate thru the Values Array and check the type directly. but don’t access the Values property to often, because it does always a .Clone() on the internal values array.
if you just want to display the typeTag string to the user or so, it would be handy to get it as a property, thats right. you could add code to the OSCMessage.cs like:
code(lang=csharp):
public string TypeTag
{
get {return typeTag;}
}
to be arrogant :)
i think this is a pretty good implementation of the VVVV .NET interface for OSC that you’re looking at: https://github.com/elliotwoods/VVVV.Nodes.OSC
There’s all the source code for a set of nodes there