/*
*
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*
*/
using LibPDBinding.Native;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace LibPDBinding
{
//the receiver part of libpd
public static partial class LibPD
{
#region Events
//private delegate field, holds the function pointer
private static LibPDPrintHook PrintHook;
private static LibPDBangHook BangHook;
private static LibPDFloatHook FloatHook;
private static LibPDSymbolHook SymbolHook;
private static LibPDListHook ListHook;
private static LibPDMessageHook MessageHook;
//import hook set method
private static void SetupHooks ()
{
//create the delegate with the method to call
PrintHook = new LibPDPrintHook (RaisePrintEvent);
Messaging.set_printhook (PrintHook);
BangHook = new LibPDBangHook (RaiseBangEvent);
Messaging.set_banghook (BangHook);
FloatHook = new LibPDFloatHook (RaiseFloatEvent);
Messaging.set_floathook (FloatHook);
SymbolHook = new LibPDSymbolHook (RaiseSymbolEvent);
Messaging.set_symbolhook (SymbolHook);
ListHook = new LibPDListHook (RaiseListEvent);
Messaging.set_listhook (ListHook);
MessageHook = new LibPDMessageHook (RaiseMessageEvent);
Messaging.set_messagehook (MessageHook);
}
///
/// Subscribe to this event in order to get PDs print messages.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.Print")]
public static event LibPDPrint Print = delegate{};
///
/// Subscribe to this event in order to get PDs bang messages.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.Bang")]
public static event LibPDBang Bang = delegate{};
///
/// Subscribe to this event in order to get PDs float messages.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.Float")]
public static event LibPDFloat Float = delegate{};
///
/// Subscribe to this event in order to get PDs symbol messages.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.Symbol")]
public static event LibPDSymbol Symbol = delegate{};
///
/// Subscribe to this event in order to get PDs list messages. Currently only
/// float and symbol types are supported. Other types in the list such as pointers will be null.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.List")]
public static event LibPDList List = delegate{};
///
/// Subscribe to this event in order to get PDs typed messages. Currently only
/// float and symbol types are supported. Other types in the list such as pointers will be null.
/// Note: Events may be raised by several threads, such as the GUI thread and
/// the audio thread. If a subscriber method calls operations that must be executed
/// in a particular thread, then the subscriber method is responsible for posting
/// those calls to the appropriate synchronization context.
///
[Obsolete ("Use LibPDBinding.Managed.Messaging.Message")]
public static event LibPDMessage Message = delegate{};
private static void RaisePrintEvent (string e)
{
Print (e);
}
private static void RaiseBangEvent (string recv)
{
Bang (recv);
}
private static void RaiseFloatEvent (string recv, float e)
{
Float (recv, e);
}
private static void RaiseSymbolEvent (string recv, string e)
{
Symbol (recv, e);
}
private static void RaiseListEvent (string recv, int argc, IntPtr argv)
{
List (recv, ConvertList (argc, argv));
}
private static void RaiseMessageEvent (string recv, string msg, int argc, IntPtr argv)
{
Message (recv, msg, ConvertList (argc, argv));
}
private static object[] ConvertList (int argc, IntPtr argv)
{
var args = new object[argc];
for (int i = 0; i < argc; i++) {
if (i != 0)
argv = Messaging.next_atom (argv);
if (Messaging.atom_is_float (argv) != 0) {
args [i] = Messaging.atom_get_float (argv);
} else if (Messaging.atom_is_symbol (argv) != 0) {
args [i] = Marshal.PtrToStringAnsi (Messaging.atom_get_symbol (argv));
}
}
return args;
}
#endregion Events
#region Message sending
///
/// If set to true each sent message will be written to Debug output
///
[Obsolete]
public static bool WriteMessageToDebug {
[MethodImpl(MethodImplOptions.Synchronized)]
get {
return SWriteMessageToDebug;
}
[MethodImpl(MethodImplOptions.Synchronized)]
set {
SWriteMessageToDebug = value;
}
}
private static bool SWriteMessageToDebug;
//binding-----------------------------------
//store bindings
private static Dictionary Bindings = new Dictionary ();
///
/// subscribes to pd messages sent to the given symbol
///
///
/// true on success
[MethodImpl (MethodImplOptions.Synchronized)]
[Obsolete ("Use LibPDBinding.Managed.Messaging.Subscribe()")]
public static bool Subscribe (string sym)
{
if (String.IsNullOrEmpty (sym))
return false;
if (Bindings.ContainsKey (sym))
return true;
var ptr = Messaging.bind (sym);
if (ptr == IntPtr.Zero)
return false;
Bindings [sym] = ptr;
return true;
}
///
/// unsubscribes from pd messages sent to the given symbol; will do nothing
/// if there is no subscription to this symbol
///
///
/// true if unsubscribed
[MethodImpl (MethodImplOptions.Synchronized)]
public static bool Unsubscribe (string sym)
{
if (String.IsNullOrEmpty (sym) || !Bindings.ContainsKey (sym))
return false;
Messaging.unbind (Bindings [sym]);
return Bindings.Remove (sym);
}
//sending-----------------------------------------------------------
///
/// sends a bang to the object associated with the given symbol
///
///
/// symbol associated with receiver
/// error code, 0 on success
[Obsolete ("Use LibPDBinding.Managed.Messaging.Send()")]
[MethodImpl (MethodImplOptions.Synchronized)]
public static int SendBang (string recv)
{
return Messaging.send_bang (recv);
}
///
/// sends a float to the object associated with the given symbol
///
///
/// symbol associated with receiver
///
/// error code, 0 on success
[Obsolete ("Use LibPDBinding.Managed.Messaging.Send()")]
[MethodImpl (MethodImplOptions.Synchronized)]
public static int SendFloat (string recv, float x)
{
return Messaging.send_float (recv, x);
}
///
/// sends a symbol to the object associated with the given symbol
///
///
/// symbol associated with receiver
///
/// error code, 0 on success
[Obsolete ("Use LibPDBinding.Managed.Messaging.Send()")]
[MethodImpl (MethodImplOptions.Synchronized)]
public static int SendSymbol (string recv, string sym)
{
return Messaging.send_symbol (recv, sym);
}
///
/// Sends a message to an object in pd
///
///
///
/// list of arguments of type Integer, Float, or String
/// error code, 0 on success
[Obsolete ("Use LibPDBinding.Managed.Messaging.Send()")]
[MethodImpl (MethodImplOptions.Synchronized)]
public static int SendMessage (string receiver, string message, params object[] args)
{
var s = "";
int err = ProcessArgs (args, ref s);
var ret = (err == 0) ? Messaging.finish_message (receiver, message) : err;
if (SWriteMessageToDebug) {
s = String.Format ("Message: {0} {1}", receiver, message) + s;
s += " Start: " + err;
s += " End: " + ret;
Debug.WriteLine (s);
}
return ret;
}
///
/// Sends a list to an object in pd
///
///
/// list of arguments of type Integer, Float, or String
/// error code, 0 on success
[Obsolete ("Use LibPDBinding.Managed.Messaging.Send()")]
[MethodImpl (MethodImplOptions.Synchronized)]
public static int SendList (string receiver, params object[] args)
{
string s = "";
int err = ProcessArgs (args, ref s);
var ret = (err == 0) ? Messaging.finish_list (receiver) : err;
if (SWriteMessageToDebug) {
s = String.Format ("List: {0}", receiver) + s;
s += " Start: " + err;
s += " End: " + ret;
Debug.WriteLine (s);
}
return ret;
}
//parse args helper with debug string
private static int ProcessArgs (object[] args, ref string debug)
{
if (Messaging.start_message (args.Length) != 0) {
return -100;
}
foreach (object arg in args) {
if (arg is int?) {
Messaging.add_float ((int)((int?)arg));
if (SWriteMessageToDebug)
debug += " i:" + arg.ToString ();
} else if (arg is float?) {
Messaging.add_float ((float)((float?)arg));
if (SWriteMessageToDebug)
debug += " f:" + arg.ToString ();
} else if (arg is double?) {
Messaging.add_float ((float)((double?)arg));
if (SWriteMessageToDebug)
debug += " d:" + arg.ToString ();
} else if (arg is string) {
Messaging.add_symbol ((string)arg);
if (SWriteMessageToDebug)
debug += " s:" + arg.ToString ();
} else {
if (SWriteMessageToDebug)
debug += " illegal argument: " + arg.ToString ();
return -101; // illegal argument
}
}
return 0;
}
#endregion Message sending
}
}