diff options
Diffstat (limited to 'PureData')
-rwxr-xr-x | PureData/Atom.cs | 55 | ||||
-rw-r--r-- | PureData/DynamicMethod.cs | 101 | ||||
-rw-r--r-- | PureData/PureData.cs | 666 | ||||
-rw-r--r-- | PureData/PureData.csproj | 213 |
4 files changed, 793 insertions, 242 deletions
diff --git a/PureData/Atom.cs b/PureData/Atom.cs index 6bad0b6..4e78eef 100755 --- a/PureData/Atom.cs +++ b/PureData/Atom.cs @@ -8,38 +8,57 @@ using System.Collections.Generic; namespace PureData { [StructLayout (LayoutKind.Sequential)] - public unsafe struct Symbol + public struct Symbol { // this should NOT be public (or at least read only) - private readonly void *sym; + private readonly IntPtr sym; public Symbol(string s) { - sym = Internal.SymGen(s); + this = Internal.SymGen(s); } public override string ToString() { - return Internal.SymEval(sym); + return Internal.SymEval(this); + } + + public static bool operator ==(Symbol s1,Symbol s2) + { + return s1.sym == s2.sym; + } + + public static bool operator !=(Symbol s1, Symbol s2) + { + return s1.sym != s2.sym; + } + + public override bool Equals(object o) + { + try { return this == (Symbol)o; } + catch {} + return false; + } + + public override int GetHashCode() + { + return (int)sym; } } [StructLayout (LayoutKind.Sequential)] - public unsafe struct Pointer + public struct Pointer { - private readonly void *ptr; + private readonly IntPtr ptr; public override string ToString() { - if(sizeof(void *) == 4) - return ((int)ptr).ToString(); - else - return ((long)ptr).ToString(); + return ptr.ToString(); } } [StructLayout (LayoutKind.Sequential)] - public unsafe struct Atom + public struct Atom { private enum AtomType {Null = 0, Float = 1, Symbol = 2, Pointer = 3}; @@ -146,7 +165,7 @@ namespace PureData } } - public class AtomListEnum + internal class AtomListEnum : IEnumerator { public AtomList list; @@ -192,8 +211,8 @@ namespace PureData // with l also being an AtomList... the two private members of the struct will get copied, although atoms is only a temporary reference [StructLayout (LayoutKind.Sequential)] - unsafe public struct AtomList -#if NET_2_0 + internal unsafe struct AtomList +#if xNET_2_0 : ICollection<Atom> #else : ICollection @@ -203,7 +222,7 @@ namespace PureData private readonly Atom *atoms; public int Count { get { return len; } } -#if NET_2_0 +#if xNET_2_0 public bool IsReadOnly { get { return false; } } // member of generic.ICollection<Atom> (C# 2.0) #endif public bool IsSynchronized { get { return false; } } @@ -212,7 +231,7 @@ namespace PureData // protect this from being used private AtomList(AtomList a) { len = 0; atoms = null; } -#if NET_2_0 +#if xNET_2_0 public void CopyTo(Atom[] array,int start) #else public void CopyTo(Array array,int start) @@ -246,7 +265,7 @@ namespace PureData } } -#if !NET_2_0 +//#if 1 // !NET_2_0 public static explicit operator Atom[](AtomList l) { Atom[] ret = new Atom[l.Count]; @@ -254,7 +273,7 @@ namespace PureData for(i = 0; i < l.Count; ++i) ret[i] = l.atoms[i]; return ret; } -#endif +//#endif override public string ToString() { diff --git a/PureData/DynamicMethod.cs b/PureData/DynamicMethod.cs new file mode 100644 index 0000000..749bb1a --- /dev/null +++ b/PureData/DynamicMethod.cs @@ -0,0 +1,101 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace PureData +{ + public delegate void DynamicMethodBang(External target); + public delegate void DynamicMethodFloat(External target,float f); + public delegate void DynamicMethodSymbol(External target,Symbol s); + public delegate void DynamicMethodPointer(External target,Pointer p); + public delegate void DynamicMethodList(External target,Atom[] l); + public delegate void DynamicMethodAnything(External target,int i,Symbol s,Atom[] l); + public delegate void DynamicMethodObject(External target,int i,object o); + + class DynamicMethods + { + private static Delegate CreateIntern(Delegate del, Type dyntype) + { + MethodInfo dynmethod = dyntype.GetMethod("Invoke"); + ParameterInfo[] dynparms = dynmethod.GetParameters(); + MethodInfo method = del.Method; + +#if DEBUG + if (dynmethod.ReturnType != typeof(void)) throw new ArgumentException("Return type must be void"); + + ParameterInfo[] parms = method.GetParameters(); + int numparms = parms.Length; + + if (dynparms.Length != numparms + 1) throw new ArgumentException("Number of parameters don't match"); + + for (int i = 0; i < numparms; ++i) + if (dynparms[i + 1].ParameterType != parms[i].ParameterType) throw new ArgumentException("Parameter types don't match"); +#endif + + Type[] argtypes = new Type[dynparms.Length]; + for (int i = 0; i < dynparms.Length; ++i) + argtypes[i] = dynparms[i].ParameterType; + + // Create dynamic method and obtain its IL generator to inject code. + DynamicMethod dynam = new DynamicMethod("dummy", typeof(void), argtypes, typeof(DynamicMethods)); + ILGenerator il = dynam.GetILGenerator(); + + #region IL Code generation + // If method isn't static push target instance on top of stack. + if (!method.IsStatic) + // Argument 0 of dynamic method is target instance. + il.Emit(OpCodes.Ldarg_0); + + // Push parameters onto the stack + for (int i = 0; i < dynparms.Length - 1; ++i) + il.Emit(OpCodes.Ldarg, i + 1); + + // Perform actual call. + // If method is not final a callvirt is required otherwise a normal call will be emitted. + il.Emit(method.IsFinal ? OpCodes.Call : OpCodes.Callvirt, method); + + // Emit return opcode. + il.Emit(OpCodes.Ret); + #endregion + + return dynam.CreateDelegate(dyntype); + } + + #region Specialized DynamicMethod makers + public static DynamicMethodBang Create(Public.MethodBang method) + { + return (DynamicMethodBang)CreateIntern(method, typeof(DynamicMethodBang)); + } + + public static DynamicMethodFloat Create(Public.MethodFloat method) + { + return (DynamicMethodFloat)CreateIntern(method,typeof(DynamicMethodFloat)); + } + + public static DynamicMethodSymbol Create(Public.MethodSymbol method) + { + return (DynamicMethodSymbol)CreateIntern(method,typeof(DynamicMethodSymbol)); + } + + public static DynamicMethodPointer Create(Public.MethodPointer method) + { + return (DynamicMethodPointer)CreateIntern(method,typeof(DynamicMethodPointer)); + } + + public static DynamicMethodList Create(Public.MethodList method) + { + return (DynamicMethodList)CreateIntern(method,typeof(DynamicMethodList)); + } + + public static DynamicMethodAnything Create(Public.MethodAnything method) + { + return (DynamicMethodAnything)CreateIntern(method,typeof(DynamicMethodAnything)); + } + + public static DynamicMethodObject Create(Public.MethodObject method) + { + return (DynamicMethodObject)CreateIntern(method, typeof(DynamicMethodObject)); + } + #endregion + } +} diff --git a/PureData/PureData.cs b/PureData/PureData.cs index 4df716e..0174317 100644 --- a/PureData/PureData.cs +++ b/PureData/PureData.cs @@ -1,203 +1,637 @@ using System; using System.Runtime.CompilerServices; // for extern import using System.Runtime.InteropServices; // for structures +using System.Reflection; +using System.Collections; namespace PureData { + [StructLayout(LayoutKind.Sequential)] + internal struct ClassPtr + { + private IntPtr ptr; + + public void Clear() { ptr = IntPtr.Zero; } + public bool Valid() { return ptr != IntPtr.Zero; } + + public override string ToString() { return ptr.ToString(); } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ExternalPtr + { + private IntPtr ptr; + + public void Clear() { ptr = IntPtr.Zero; } + public bool Valid() { return ptr != IntPtr.Zero; } + + public override string ToString() { return ptr.ToString(); } + } + + // data passed from/to native side + [StructLayout(LayoutKind.Sequential)] + internal class PassedData + { + public Class klass; + public External ext; + public object obj; + } + // PD core functions - public unsafe class Internal + public class Internal { - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void *SymGen(string sym); + // the ExternalPtr when initializing an External instance + internal static ExternalPtr extptr; - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static string SymEval(void *sym); + internal static PassedData pass; // -------------------------------------------------------------------------- + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static Symbol SymGen(string sym); + [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,Symbol sel,Symbol to_sel); + internal extern static string SymEval(Symbol sym); + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, Symbol sel, Symbol to_sel); // map to data member - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,ref float f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, ref float f); // map to data member - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,ref Symbol s); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, ref Symbol s); // map to data member -// [MethodImplAttribute (MethodImplOptions.InternalCall)] -// internal extern static void AddInlet(void *obj,ref Pointer f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj,ref Pointer f); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,Symbol type); // create proxy inlet (typed) + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, Symbol type); // create proxy inlet (typed) - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj); // create proxy inlet (anything) + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj); // create proxy inlet (anything) // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddOutlet(void *obj,Symbol type); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddOutlet(ExternalPtr obj, Symbol type); // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,float f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void Outlet(ExternalPtr obj, int n); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s); + internal extern static void Outlet(ExternalPtr obj, int n, float f); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Pointer p); + internal extern static void Outlet(ExternalPtr obj, int n, Symbol s); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Atom a); + internal extern static void Outlet(ExternalPtr obj, int n, Pointer p); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s,AtomList l); + internal extern static void Outlet(ExternalPtr obj, int n, Atom a); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s,Atom[] l); + internal extern static void Outlet(ExternalPtr obj, int n, Symbol s, Atom[] l); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void OutletEx(void *obj,int n,object o); + internal extern static void OutletEx(ExternalPtr obj, int n, object o); // -------------------------------------------------------------------------- [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Bind(void *obj,Symbol dst); + internal extern static void Bind(ExternalPtr obj, Symbol dst); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Unbind(void *obj,Symbol dst); + internal extern static void Unbind(ExternalPtr obj, Symbol dst); } - - // This is the base class for a PD/CLR external - public unsafe abstract class External - { - // PD object pointer - private readonly void *ptr; + + public abstract class Public + : Internal + { // to be returned by Setup function - protected enum ClassType { Default = 0,PD = 1,GObj = 2,Patchable = 3,NoInlet = 8 } + protected enum ClassType { Default = 0, PD = 1, GObj = 2, Patchable = 3, NoInlet = 8 } // -------------------------------------------------------------------------- - protected readonly static Symbol _ = new Symbol(""); - protected readonly static Symbol _bang = new Symbol("bang"); - protected readonly static Symbol _float = new Symbol("float"); - protected readonly static Symbol _symbol = new Symbol("symbol"); - protected readonly static Symbol _pointer = new Symbol("pointer"); - protected readonly static Symbol _list = new Symbol("list"); - protected readonly static Symbol _anything = new Symbol("anything"); + public delegate void MethodBang(); + public delegate void MethodFloat(float f); + public delegate void MethodSymbol(Symbol s); + public delegate void MethodPointer(Pointer p); + public delegate void MethodList(Atom[] lst); + public delegate void MethodAnything(int inlet, Symbol tag, Atom[] lst); + public delegate void MethodObject(int inlet, object o); // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void Post(string message); - - protected static void Post(string format,object arg0) { Post(String.Format(format,arg0)); } - protected static void Post(string format,object arg0,object arg1) { Post(String.Format(format,arg0,arg1)); } - protected static void Post(string format,object arg0,object arg1,object arg2) { Post(String.Format(format,arg0,arg1,arg2)); } - protected static void Post(string format,params object[] args) { Post(String.Format(format,args)); } - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void PostError(string message); - - protected static void PostError(string format,object arg0) { PostError(String.Format(format,arg0)); } - protected static void PostError(string format,object arg0,object arg1) { PostError(String.Format(format,arg0,arg1)); } - protected static void PostError(string format,object arg0,object arg1,object arg2) { PostError(String.Format(format,arg0,arg1,arg2)); } - protected static void PostError(string format,params object[] args) { PostError(String.Format(format,args)); } - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void PostVerbose(int lvl,string message); - - protected static void PostVerbose(int lvl,string format,object arg0) { PostVerbose(lvl,String.Format(format,arg0)); } - protected static void PostVerbose(int lvl,string format,object arg0,object arg1) { PostVerbose(lvl,String.Format(format,arg0,arg1)); } - protected static void PostVerbose(int lvl,string format,object arg0,object arg1,object arg2) { PostVerbose(lvl,String.Format(format,arg0,arg1,arg2)); } - protected static void PostVerbose(int lvl,string format,params object[] args) { PostVerbose(lvl,String.Format(format,args)); } + public readonly static Symbol _ = new Symbol(""); + public readonly static Symbol _bang = new Symbol("bang"); + public readonly static Symbol _float = new Symbol("float"); + public readonly static Symbol _symbol = new Symbol("symbol"); + public readonly static Symbol _pointer = new Symbol("pointer"); + public readonly static Symbol _list = new Symbol("list"); // -------------------------------------------------------------------------- - protected delegate void Method(); - protected delegate void MethodFloat(float f); - protected delegate void MethodSymbol(Symbol s); - protected delegate void MethodPointer(Pointer p); - protected delegate void MethodList(AtomList lst); - protected delegate void MethodAnything(int inlet,Symbol tag,AtomList lst); - protected delegate void MethodObject(int inlet,object o); + [MethodImplAttribute (MethodImplOptions.InternalCall)] + public extern static void Post(string message); - // -------------------------------------------------------------------------- + public static void Post(string format, object arg0) { Post(String.Format(format, arg0)); } + public static void Post(string format, object arg0, object arg1) { Post(String.Format(format, arg0, arg1)); } + public static void Post(string format, object arg0, object arg1, object arg2) { Post(String.Format(format, arg0, arg1, arg2)); } + public static void Post(string format, params object[] args) { Post(String.Format(format, args)); } [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Method m); + public extern static void PostError(string message); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodFloat m); + public static void PostError(string format, object arg0) { PostError(String.Format(format, arg0)); } + public static void PostError(string format, object arg0, object arg1) { PostError(String.Format(format, arg0, arg1)); } + public static void PostError(string format, object arg0, object arg1, object arg2) { PostError(String.Format(format, arg0, arg1, arg2)); } + public static void PostError(string format, params object[] args) { PostError(String.Format(format, args)); } [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodSymbol m); + public extern static void PostVerbose(int lvl, string message); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodPointer m); + public static void PostVerbose(int lvl, string format, object arg0) { PostVerbose(lvl, String.Format(format, arg0)); } + public static void PostVerbose(int lvl, string format, object arg0, object arg1) { PostVerbose(lvl, String.Format(format, arg0, arg1)); } + public static void PostVerbose(int lvl, string format, object arg0, object arg1, object arg2) { PostVerbose(lvl, String.Format(format, arg0, arg1, arg2)); } + public static void PostVerbose(int lvl, string format, params object[] args) { PostVerbose(lvl, String.Format(format, args)); } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodList m); + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodAnything m); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public extern static string SearchPath(string file); + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,Method m); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodFloat m); + public sealed class Class + : Public + { + // PD class pointer + private readonly ClassPtr ptr; + + // class type + private Type extclass; + + // -------------------------------------------------------------------------- + + // simple methods for inlet 0 + private DynamicMethodBang m_bang = null; + private DynamicMethodFloat m_float = null; + private DynamicMethodSymbol m_symbol = null; + private DynamicMethodPointer m_pointer = null; + private DynamicMethodList m_list = null; + private DynamicMethodAnything m_anything = null; + private DynamicMethodObject m_object = null; + + // -------------------------------------------------------------------------- + + private static void ResizeArray(ref Hashtable[] oldArray, int newSize) + { + int oldSize = oldArray.Length; + System.Type elementType = oldArray.GetType().GetElementType(); + Hashtable[] newArray = (Hashtable[])System.Array.CreateInstance(elementType, newSize); + int preserveLength = System.Math.Min(oldSize, newSize); + if (preserveLength > 0) + System.Array.Copy(oldArray, newArray, preserveLength); + oldArray = newArray; + } + + private struct MapValue + { + public MapValue(Kind k,Delegate d) { this.k = k; this.d = d; } + + public Kind k; + public Delegate d; + } + + private Hashtable[] m_map = new Hashtable[0]; + + // -------------------------------------------------------------------------- + + public override string ToString() + { + return extclass.Name; + } + + // -------------------------------------------------------------------------- + + private enum Kind { k_bang, k_float, k_symbol, k_pointer, k_list, k_anything, k_object } + + private enum MethodFlags { f_none = 0,f_bang = 0x01, f_float = 0x02, f_symbol = 0x04, f_pointer = 0x08, f_list = 0x10, f_anything = 0x20 } + + private static MethodFlags methodflags; + + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern static bool RegisterClass(ClassPtr ptr, Symbol sym, ClassType cflags, MethodFlags mflags); + + private void AddMethodIntern(int inlet, Symbol sel, Kind k, Delegate d) + { + // add to map + if (m_map.Length <= inlet) ResizeArray(ref m_map, inlet + 1); + Hashtable h = m_map[inlet]; + if(h == null) m_map[inlet] = h = new Hashtable(); + h[sel] = new MapValue(k, d); + + methodflags |= MethodFlags.f_anything; + } + + public void AddMethod(int inlet, Symbol sel, MethodBang d) + { + DynamicMethodBang dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _bang) + { + m_bang = dyn; + methodflags |= MethodFlags.f_bang; + } + else + AddMethodIntern(inlet, sel, Kind.k_bang, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodFloat d) + { + DynamicMethodFloat dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _float) + { + m_float = dyn; + methodflags |= MethodFlags.f_float; + } + else + AddMethodIntern(inlet, sel, Kind.k_float, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodSymbol d) + { + DynamicMethodSymbol dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _symbol) + { + m_symbol = dyn; + methodflags |= MethodFlags.f_symbol; + } + else + AddMethodIntern(inlet, sel, Kind.k_symbol, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodPointer d) + { + DynamicMethodPointer dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _pointer) + { + m_pointer = dyn; + methodflags |= MethodFlags.f_pointer; + } + else + AddMethodIntern(inlet, sel, Kind.k_pointer, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodList d) + { + DynamicMethodList dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _list) + { + m_list = dyn; + methodflags |= MethodFlags.f_list; + } + else + AddMethodIntern(inlet, sel, Kind.k_list, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodAnything d) + { + DynamicMethodAnything dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _) + { + m_anything = dyn; + methodflags |= MethodFlags.f_anything; + } + else + AddMethodIntern(inlet, sel, Kind.k_anything, dyn); + } + + public void AddMethod(int inlet, MethodObject d) + { + DynamicMethodObject dyn = DynamicMethods.Create(d); + m_object = dyn; + methodflags |= MethodFlags.f_anything; + } + + // -------------------------------------------------------------------------- + + private Class(ClassPtr p,Type c) + { + ptr = p; + extclass = c; + } + + private delegate void DelegateClass(ClassPtr ptr, Symbol sym); + private static void NewClass(ClassPtr ptr, Symbol sym) + { + Internal.pass.klass = null; + + try + { + string name = sym.ToString(); + + // load assembly according to name + string file = SearchPath(name + ".dll"); + if (file.Length == 0) return; // throw new ArgumentException("Assembly file " + name + " not found"); + Assembly assembly = Assembly.LoadFile(file); + if (assembly == null) return; // throw new ArgumentException("Assembly " + name + " could not be loaded"); + Type exttp = assembly.GetType(name); + if (exttp == null) throw new ArgumentException("Class " + name + " could not be found"); + + Class klass = new Class(ptr, exttp); + + // create dummy external + ConstructorInfo ctor = exttp.GetConstructor(System.Type.EmptyTypes); + if (ctor == null) throw new MissingMethodException("External class must have a default constructor"); + + Internal.pass.klass = klass; + Internal.extptr.Clear(); + + External dummy = (External)ctor.Invoke(null); + + // reset flags + methodflags = MethodFlags.f_none; + + // call Setup method + MethodInfo setup = exttp.GetMethod("Setup",BindingFlags.NonPublic|BindingFlags.Static,null, new Type[1] { exttp },null); + if (setup == null) throw new MissingMethodException("External class must have a Setup function"); + + object ret = setup.Invoke(exttp, new object[1] { dummy }); + ClassType classflags; + try { classflags = (ClassType)ret; } + catch { classflags = ClassType.Default; } + + // set callbacks + RegisterClass(ptr, sym, classflags, methodflags); + } + catch (Exception exc) + { + Internal.pass.klass = null; + PostError(exc.ToString()); + } + } + + private delegate void DelegateNew(ExternalPtr ptr,AtomList args); + private static void NewInstance(ExternalPtr ptr,AtomList args) + { + External instance; + + Class cl = Internal.pass.klass; // set by native side + Internal.extptr = ptr; + +// Post("CLASS-NEW {0}",cl); + try + { + // TODO: create dynamic delegate for that.... + System.Reflection.ConstructorInfo m = cl.extclass.GetConstructor(new Type[1] { typeof(Atom[]) }); + if (m != null) + instance = (External)m.Invoke(new object[1] { (Atom[])args }); + else + { + // search for the argument-less constructor... it must exist, we searched before + m = cl.extclass.GetConstructor(System.Type.EmptyTypes); + instance = (External)m.Invoke(null); + } + } + catch (Exception exc) + { + instance = null; + PostError(exc.ToString()); + } + +#if DEBUG + Internal.extptr.Clear(); +#endif + + Internal.pass.ext = instance; // back to native + } + + private delegate void DelegateBang(); + private static void CallBang() + { + External e = Internal.pass.ext; + try { e.klass.m_bang(e); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateFloat(float f); + private static void CallFloat(float f) + { + External e = Internal.pass.ext; + try { e.klass.m_float(e, f); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateSymbol(Symbol s); + private static void CallSymbol(Symbol s) + { + External e = Internal.pass.ext; + try { e.klass.m_symbol(e, s); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegatePointer(Pointer p); + private static void CallPointer(Pointer p) + { + External e = Internal.pass.ext; + try { e.klass.m_pointer(e, p); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateList(AtomList l); + private static void CallList(AtomList l) + { + External e = Internal.pass.ext; + try { e.klass.m_list(e, (Atom[])l); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateAnything(int inlet, Symbol s, AtomList l); + private static void CallAnything(int inlet, Symbol s, AtomList l) + { +// Post("CLASS-ANYTHING {0}->{1}:{2}", inlet,s,l); + + try { + External e = Internal.pass.ext; + Class c = e.klass; + + Hashtable h; + try { h = (Hashtable)c.m_map[inlet]; } + catch (IndexOutOfRangeException) { h = null; } + + if(h != null) + { + object fnd = h[s]; + if (fnd != null) + { + MapValue mv = (MapValue)fnd; + switch(mv.k) + { + case Kind.k_bang: + { + ((DynamicMethodBang)mv.d)(e); + return; + } + case Kind.k_float: + { + float f = l.Count > 0 ? (float)l[0] : 0; + ((DynamicMethodFloat)mv.d)(e, f); + return; + } + case Kind.k_symbol: + { + Symbol sym = l.Count > 0 ? (Symbol)l[0] : _; + ((DynamicMethodSymbol)mv.d)(e, sym); + return; + } + case Kind.k_pointer: + { + Pointer p = l.Count > 0 ? (Pointer)l[0] : new Pointer(); + ((DynamicMethodPointer)mv.d)(e, p); + return; + } + case Kind.k_list: + ((DynamicMethodList)mv.d)(e,(Atom[])l); + return; + case Kind.k_anything: + ((DynamicMethodAnything)mv.d)(e,inlet,s,(Atom[])l); + return; + default: + throw new NotImplementedException("Selector " + s.ToString() + " not handled"); + } + } + } + + // no explicit method found... + c.m_anything(e, inlet, s, (Atom[])l); + } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateObject(int inlet); + private static void CallObject(int inlet) + { +// Post("CLASS-OBJECT {0}", inlet); + + External e = Internal.pass.ext; + try { e.klass.m_object(e, inlet, Internal.pass.obj); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern static void Register(DelegateClass d_class, DelegateNew d_new, DelegateBang d_bang, DelegateFloat d_float, DelegateSymbol d_symbol, DelegatePointer d_pointer, DelegateList d_list, DelegateAnything d_anything, DelegateObject d_object); + + private static void Setup() + { + try + { + Internal.pass = new PassedData(); + + Register( + new DelegateClass(NewClass), + new DelegateNew(NewInstance), + new DelegateBang(CallBang), + new DelegateFloat(CallFloat), + new DelegateSymbol(CallSymbol), + new DelegatePointer(CallPointer), + new DelegateList(CallList), + new DelegateAnything(CallAnything), + new DelegateObject(CallObject) + ); + } + catch (Exception exc) { PostError(exc.ToString()); } + } + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodSymbol m); + + // This is the base class for a PD/CLR external + public abstract class External + : Public + { + // PD object pointer + internal readonly ExternalPtr ptr; + // Class + internal readonly Class klass; - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodPointer m); + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodList m); + protected External() + { + ptr = Internal.extptr; + klass = Internal.pass.klass; + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodAnything m); + public override string ToString() + { + return ptr.Valid()?klass.ToString():"???"; + } - protected static void AddMethod(int inlet,string sel,Method m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodFloat m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodSymbol m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodPointer m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodList m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodAnything m) { AddMethod(inlet,new Symbol(sel),m); } + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodObject m); + protected static void AddMethod(int inlet, Symbol sel, MethodBang m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodFloat m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodSymbol m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodPointer m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodList m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodAnything m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, MethodObject m) { ((External)m.Target).klass.AddMethod(inlet, m); } + + protected static void AddMethod(int inlet, MethodBang m) { AddMethod(inlet, _bang, m); } + protected static void AddMethod(int inlet, MethodFloat m) { AddMethod(inlet, _float, m); } + protected static void AddMethod(int inlet, MethodSymbol m) { AddMethod(inlet, _symbol, m); } + protected static void AddMethod(int inlet, MethodPointer m) { AddMethod(inlet, _pointer, m); } + protected static void AddMethod(int inlet, MethodList m) { AddMethod(inlet, _list, m); } + protected static void AddMethod(int inlet, MethodAnything m) { AddMethod(inlet, _, m); } + + protected static void AddMethod(MethodBang m) { AddMethod(0, m); } + protected static void AddMethod(MethodFloat m) { AddMethod(0, m); } + protected static void AddMethod(MethodSymbol m) { AddMethod(0, m); } + protected static void AddMethod(MethodPointer m) { AddMethod(0, m); } + protected static void AddMethod(MethodList m) { AddMethod(0, m); } + protected static void AddMethod(MethodAnything m) { AddMethod(0, m); } + protected static void AddMethod(MethodObject m) { AddMethod(0, m); } + + protected static void AddMethod(int inlet, string sel, MethodBang m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodFloat m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodSymbol m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodPointer m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodList m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodAnything m) { AddMethod(inlet, new Symbol(sel), m); } // -------------------------------------------------------------------------- - protected void AddInlet(ref float f) { Internal.AddInlet(ptr,ref f); } // map to data member - protected void AddInlet(ref Symbol s) { Internal.AddInlet(ptr,ref s); } // map to data member -// protected void AddInlet(ref Pointer p) { Internal.AddInlet(ptr,ref p); } // map to data member + protected void AddInlet(ref float f) { Internal.AddInlet(ptr, ref f); } // map to data member + protected void AddInlet(ref Symbol s) { Internal.AddInlet(ptr, ref s); } // map to data member + protected void AddInlet(ref Pointer p) { Internal.AddInlet(ptr,ref p); } // map to data member // protected void AddInlet(Symbol type) { Internal.AddInlet(ptr,type); } // create typed inlet protected void AddInlet() { Internal.AddInlet(ptr); } // create inlet responding to any message - protected void AddInlet(Symbol sel,Symbol to_sel) { Internal.AddInlet(ptr,sel,to_sel); } // redirect messages to defined selector + protected void AddInlet(Symbol sel, Symbol to_sel) { Internal.AddInlet(ptr, sel, to_sel); } // redirect messages to defined selector // -------------------------------------------------------------------------- - protected void AddOutlet(Symbol type) { Internal.AddOutlet(ptr,type); } + protected void AddOutlet(Symbol type) { Internal.AddOutlet(ptr, type); } protected void AddOutletBang() { AddOutlet(_bang); } protected void AddOutletFloat() { AddOutlet(_float); } protected void AddOutletSymbol() { AddOutlet(_symbol); } protected void AddOutletPointer() { AddOutlet(_pointer); } protected void AddOutletList() { AddOutlet(_list); } - protected void AddOutletAnything() { AddOutlet(_anything); } + protected void AddOutletAnything() { AddOutlet(_); } // -------------------------------------------------------------------------- @@ -206,9 +640,7 @@ namespace PureData protected void Outlet(int n,Symbol s) { Internal.Outlet(ptr,n,s); } protected void Outlet(int n,Pointer p) { Internal.Outlet(ptr,n,p); } protected void Outlet(int n,Atom a) { Internal.Outlet(ptr,n,a); } - protected void Outlet(int n,AtomList l) { Internal.Outlet(ptr,n,_list,l); } protected void Outlet(int n,Atom[] l) { Internal.Outlet(ptr,n,_list,l); } - protected void Outlet(int n,Symbol s,AtomList l) { Internal.Outlet(ptr,n,s,l); } protected void Outlet(int n,Symbol s,Atom[] l) { Internal.Outlet(ptr,n,s,l); } protected void OutletEx(int n,object o) { Internal.OutletEx(ptr,n,o); } @@ -223,17 +655,13 @@ namespace PureData [MethodImplAttribute (MethodImplOptions.InternalCall)] protected extern static void Send(Symbol sym,Atom a); - protected static void Send(Symbol sym) { Send(sym,_bang,null); } + protected static void Send(Symbol sym) { Send(sym,_bang,new Atom[0]); } protected static void Send(Symbol sym,float f) { Send(sym,new Atom(f)); } protected static void Send(Symbol sym,Symbol s) { Send(sym,new Atom(s)); } protected static void Send(Symbol sym,Pointer p) { Send(sym,new Atom(p)); } - protected static void Send(Symbol sym,AtomList l) { Send(sym,_list,l); } protected static void Send(Symbol sym,Atom[] l) { Send(sym,_list,l); } [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void Send(Symbol sym,Symbol s,AtomList l); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] protected extern static void Send(Symbol sym,Symbol s,Atom[] l); [MethodImplAttribute (MethodImplOptions.InternalCall)] diff --git a/PureData/PureData.csproj b/PureData/PureData.csproj index f1b3d08..2d65f14 100644 --- a/PureData/PureData.csproj +++ b/PureData/PureData.csproj @@ -1,105 +1,108 @@ -<VisualStudioProject> - <CSHARP - ProjectType = "Local" - ProductVersion = "7.10.3077" - SchemaVersion = "2.0" - ProjectGuid = "{0015D5E7-B0FB-4F06-B334-225447D1F992}" - > - <Build> - <Settings - ApplicationIcon = "" - AssemblyKeyContainerName = "" - AssemblyName = "PureData" - AssemblyOriginatorKeyFile = "" - DefaultClientScript = "JScript" - DefaultHTMLPageLayout = "Grid" - DefaultTargetSchema = "IE50" - DelaySign = "false" - OutputType = "Library" - PreBuildEvent = "" - PostBuildEvent = "" - RootNamespace = "PureData" - RunPostBuildEvent = "OnBuildSuccess" - StartupObject = "" - > - <Config - Name = "Debug" - AllowUnsafeBlocks = "true" - BaseAddress = "285212672" - CheckForOverflowUnderflow = "false" - ConfigurationOverrideFile = "" - DefineConstants = "DEBUG;TRACE" - DocumentationFile = "" - DebugSymbols = "true" - FileAlignment = "4096" - IncrementalBuild = "false" - NoStdLib = "false" - NoWarn = "" - Optimize = "false" - OutputPath = "bin\Debug\" - RegisterForComInterop = "false" - RemoveIntegerChecks = "false" - TreatWarningsAsErrors = "false" - WarningLevel = "4" - /> - <Config - Name = "Release" - AllowUnsafeBlocks = "true" - BaseAddress = "285212672" - CheckForOverflowUnderflow = "false" - ConfigurationOverrideFile = "" - DefineConstants = "TRACE" - DocumentationFile = "" - DebugSymbols = "false" - FileAlignment = "4096" - IncrementalBuild = "false" - NoStdLib = "false" - NoWarn = "" - Optimize = "true" - OutputPath = "bin\Release\" - RegisterForComInterop = "false" - RemoveIntegerChecks = "false" - TreatWarningsAsErrors = "false" - WarningLevel = "4" - /> - </Settings> - <References> - <Reference - Name = "System" - AssemblyName = "System" - HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll" - /> - <Reference - Name = "System.Data" - AssemblyName = "System.Data" - HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll" - /> - <Reference - Name = "System.XML" - AssemblyName = "System.XML" - HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll" - /> - </References> - </Build> - <Files> - <Include> - <File - RelPath = "AssemblyInfo.cs" - SubType = "Code" - BuildAction = "Compile" - /> - <File - RelPath = "Atom.cs" - SubType = "Code" - BuildAction = "Compile" - /> - <File - RelPath = "PureData.cs" - SubType = "Code" - BuildAction = "Compile" - /> - </Include> - </Files> - </CSHARP> -</VisualStudioProject> - +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectType>Local</ProjectType> + <ProductVersion>8.0.50727</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{0015D5E7-B0FB-4F06-B334-225447D1F992}</ProjectGuid> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ApplicationIcon> + </ApplicationIcon> + <AssemblyKeyContainerName> + </AssemblyKeyContainerName> + <AssemblyName>PureData</AssemblyName> + <AssemblyOriginatorKeyFile> + </AssemblyOriginatorKeyFile> + <DefaultClientScript>JScript</DefaultClientScript> + <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout> + <DefaultTargetSchema>IE50</DefaultTargetSchema> + <DelaySign>false</DelaySign> + <OutputType>Library</OutputType> + <RootNamespace>PureData</RootNamespace> + <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent> + <StartupObject> + </StartupObject> + <FileUpgradeFlags> + </FileUpgradeFlags> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <OutputPath>bin\Debug\</OutputPath> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <BaseAddress>285212672</BaseAddress> + <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> + <ConfigurationOverrideFile> + </ConfigurationOverrideFile> + <DefineConstants>TRACE;DEBUG;NET_2_0</DefineConstants> + <DocumentationFile> + </DocumentationFile> + <DebugSymbols>true</DebugSymbols> + <FileAlignment>4096</FileAlignment> + <NoStdLib>false</NoStdLib> + <NoWarn> + </NoWarn> + <Optimize>false</Optimize> + <RegisterForComInterop>false</RegisterForComInterop> + <RemoveIntegerChecks>false</RemoveIntegerChecks> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <WarningLevel>4</WarningLevel> + <DebugType>full</DebugType> + <ErrorReport>prompt</ErrorReport> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <OutputPath>bin\Debug\</OutputPath> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <BaseAddress>285212672</BaseAddress> + <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> + <ConfigurationOverrideFile> + </ConfigurationOverrideFile> + <DefineConstants>TRACE;DEBUG;NET_2_0</DefineConstants> + <DocumentationFile> + </DocumentationFile> + <DebugSymbols>false</DebugSymbols> + <FileAlignment>4096</FileAlignment> + <NoStdLib>false</NoStdLib> + <NoWarn> + </NoWarn> + <Optimize>false</Optimize> + <RegisterForComInterop>false</RegisterForComInterop> + <RemoveIntegerChecks>false</RemoveIntegerChecks> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <WarningLevel>4</WarningLevel> + <DebugType>none</DebugType> + <ErrorReport>prompt</ErrorReport> + </PropertyGroup> + <ItemGroup> + <Reference Include="System"> + <Name>System</Name> + </Reference> + <Reference Include="System.Data"> + <Name>System.Data</Name> + </Reference> + <Reference Include="System.Xml"> + <Name>System.XML</Name> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Atom.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="DynamicMethod.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="PureData.cs"> + <SubType>Code</SubType> + </Compile> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <PropertyGroup> + <PreBuildEvent> + </PreBuildEvent> + <PostBuildEvent> + </PostBuildEvent> + </PropertyGroup> +</Project>
\ No newline at end of file |