source: cpp/frams/model/modelparts.h @ 1326

Last change on this file since 1326 was 1323, checked in by Maciej Komosinski, 4 months ago

Field rename for less ambiguity

  • Property svn:eol-style set to native
File size: 19.4 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1323]2// Copyright (C) 1999-2024  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#ifndef _MODELPARTS_H_
6#define _MODELPARTS_H_
7
8#include <frams/util/3d.h>
[121]9#include <frams/genetics/genoconv.h>
[109]10
11#include <frams/util/extvalue.h>
12#include <frams/util/list.h>
13#include <frams/util/sstring.h>
14#include <frams/util/sstringutils.h>
15#include <frams/param/param.h>
16#include <frams/param/syntparam.h>
17#include <frams/util/usertags.h>
18#include <frams/param/paramtabobj.h>
19
20#include <stdio.h>
21
22class Model;
23class IRange;
24class MultiRange;
25
[899]26typedef UserTags<Model, void *, 5> ModelUserTags;
[109]27
[934]28
29/// Introduced only because we can't have a forward declaration of enum in the Model class,
30/// and we would need a forward declaration because of mutual (cyclic) dependence of declarations of Model and NeuroClass.
31/// https://stackoverflow.com/questions/27019292/is-in-class-enum-forward-declaration-possible
32/// Use Model::... instead of ModelEnum::...
33class ModelEnum
34{
35public:
[999]36        enum ShapeType {
37                SHAPETYPE_BALL_AND_STICK = 0, SHAPETYPE_SOLIDS = 1, SHAPETYPE_UNKNOWN, SHAPETYPE_ILLEGAL, ///< 0 and 1 have special significance - these values allow for bit operations.
38                SHAPETYPE_FIRST = SHAPETYPE_BALL_AND_STICK, SHAPETYPE_LAST = SHAPETYPE_SOLIDS // for iteration
39        };
[934]40};
41
[109]42/** Common base for model elements. */
43class PartBase
44{
45public:
[714]46        SString vis_style;
[899]47        PartBase(const SString &s) :vis_style(s), mapped(0) {}
[714]48        ~PartBase();
[899]49        static SString getDefaultStyle() { return SString("none"); }
[714]50        MultiRange *mapped;
51        enum PartBaseFlags { Selected = 1 };
52        int flags;
53        Model *owner;   ///< backlink to the model
[109]54
[714]55        SString info;
[109]56
[714]57        Model &getModel() const { return *owner; }
[109]58
[714]59        ModelUserTags userdata;
[109]60
[714]61        void notifyMappingChange();
[109]62
[714]63        void clearMapping();
[899]64        MultiRange *getMapping() { return mapped; }
[714]65        void setMapping(const IRange &mr);
66        void addMapping(const IRange &mr);
67        void setMapping(const MultiRange &mr);
68        void addMapping(const MultiRange &mr);
[109]69
[899]70        void setInfo(const SString &name, const SString &value);
71        void setInfo(const SString &name, int value);
72        void setInfo(const SString &name, double value);
73        SString getInfo(const SString &name);
[109]74};
75
[999]76/// Part is the only real physical object in creatures in Framsticks.
[109]77/// You can use this class for querying and adjusting constructed
[999]78/// model properties.
[714]79class Part : public PartBase
[109]80{
[714]81        friend class Model;
82        static SString getDefaultStyle();
83        Part(double _mass, double _size, double _density, double _friction, double _ingest, double _assim)
84                :PartBase(getDefaultStyle()), mass(_mass), size(_size), density(_density), friction(_friction), ingest(_ingest), assim(_assim)
[109]85        {}
[714]86        void defassign();
[109]87public:
[714]88        // base properties - have special meaning and therefore are often accessed directly for convenience
89        Pt3D p;    ///< 3d coordinates of the part
90        Orient o;  ///< orientation in 3d space (rotation matrix)
91        /// ParamInterface object is preferred way to get/set other properties.
92        Param extraProperties();
93        Param properties();
94        paInt refno;
95        Pt3D rot;///< rotation angles
[109]96
[714]97        ///
98        paInt shape;///default=old Framsticks compatible, do not mix with shapes>0
[999]99        enum Shape {
100                SHAPE_BALL = 0, ///<  for "ball and stick" shape type model only.
[1318]101                SHAPE_ELLIPSOID = 1, SHAPE_CUBOID = 2 /* rectangular cuboid */, SHAPE_CYLINDER = 3,
[999]102                SHAPE_FIRST = SHAPE_BALL, SHAPE_LAST = SHAPE_CYLINDER // for iteration
[977]103        };
104        static const char* getShapeName(Shape sh);
[1323]105        static constexpr double BALL_AND_STICK_RADIUS = 0.15; //used in odesim, VisualModel, CreatureObj3D, and SHAPETYPE_BALL_AND_STICK to SHAPETYPE_SOLIDS Model conversion
[977]106
[714]107        double mass, size, density, friction, ingest, assim, hollow;
108        Pt3D scale;
109        Pt3D food;
110        //SList points; // collistion points
111        //Slist neurons; // "select * from owner->neurons where part=this" ;-)
[109]112
[714]113        Pt3D vcolor;
[109]114
[999]115        Part(enum Shape s = SHAPE_BALL);
[899]116        Part(const Part &src) :PartBase(getDefaultStyle()) { operator=(src); }
117        void operator=(const Part &src);
[109]118
[714]119        void setPositionAndRotationFromAxis(const Pt3D &p1, const Pt3D &p2);
120        void setOrient(const Orient &o);///< set part.o and calculates part.rot (rotation angles)
121        void setRot(const Pt3D &r);///< set part.rot (rotation angles) and calculate part.o
[109]122
[899]123        static Param &getStaticParam();
[109]124};
125
[934]126class Part_MinMaxDef : public Part //contains additional information for Model::getMinPart()/getMaxPart()/getDefPart()
127{
128public:
129        double volume; ///< Introduced to limit the range of volumes (~mass) in simulation of solids. Genetic operators should observe this min,max volume by calculating and limiting the volume of Parts based on their type and sx,sy,sz.
130
131        void defassign();
132        Part_MinMaxDef() { defassign(); }
133};
134
[109]135/// Imaginary connection between two parts.
136/// Joint has no mass nor intertia but can transfer forces.
[714]137class Joint : public PartBase
[109]138{
[714]139        friend class Model;
140        SString getDefaultStyle();
141        Joint(double _stamina, double _stif, double _rotstif, double _d)
142                :PartBase(getDefaultStyle()), stamina(_stamina), stif(_stif), rotstif(_rotstif)
143        {
144                d = Pt3D(_d, 0, 0);
145        }
146        void defassign();
147        void resetDeltaMarkers();
[109]148public:
[714]149        // base properties:
150        paInt p1_refno, p2_refno; ///< parts' reference numbers
[109]151
[714]152        Part *part1, *part2;    ///< references to parts
153        class Pt3D d;           ///< position delta between parts
154        class Pt3D rot; ///< orientation delta between parts expressed as 3 angles
[932]155        enum Shape {
[999]156                SHAPE_STICK = 0, ///<  for "ball and stick" shape type model, creates a physical (cylinder or cuboid) rod between parts. Do not mix with part.shape>0.
[932]157                SHAPE_FIXED = 1, ///< merge parts into one physical entity
158                SHAPE_HINGE_X = 2, ///< hinge connection, revolving around X axis defined by hinge_pos and hinge_rot
[977]159                SHAPE_HINGE_XY = 3, ///< double hinge connection, revolving around X and Y axes defined by hinge_pos and hinge_rot
[999]160                SHAPE_FIRST = SHAPE_STICK, SHAPE_LAST = SHAPE_HINGE_XY // for iteration
[932]161        };
[915]162        paInt shape;///< values of type Shape (paInt for integration with Param)
[977]163        static const char* getShapeName(Shape sh);
[915]164        class Pt3D hinge_pos; ///< hinge position (relative to part1) for HINGE_X and HINGE_XY
165        class Pt3D hinge_rot; ///< hinge orientation (relative to part1) for HINGE_X and HINGE_XY
166        double hinge_limit_x[2], hinge_limit_y[2]; ///< hinge movement range - i.e., extreme allowed values of a state. A state can be an angle or other physical property. limit[0] <= 0 <= limit[1]. Relative Part position and orientation as set in the Model define the initial state 0.
[109]167
[714]168        Joint();
[899]169        Joint(const Joint &src) :PartBase(getDefaultStyle()) { operator=(src); }
170        void operator=(const Joint &src);
[109]171
[714]172        /** connect two parts with this joint.
173                p2 position will be adjusted if delta option is in effect.
174                @see isDelta()
175                */
[899]176        void attachToParts(Part *p1, Part *p2);
[714]177        /// @see attachToParts(Part*,Part*)
178        void attachToParts(int p1, int p2);
[109]179
[714]180        /** discard delta information but don't disable delta flag.
181                delta will be calculated from parts positions during final consistency check.
182                */
183        void resetDelta();
[109]184
[714]185        /** enable or disable delta option.
186                delta value is not changed.
187                */
188        void useDelta(bool use);
[109]189
[714]190        /** @return true if delta option is in effect.
191                @see useDelta(), resetDelta(), useDelta()
192                */
193        bool isDelta();
[109]194
[714]195        /// ParamInterface object is preferred way to get/set other properties.
196        Param extraProperties();
197        Param properties();
[109]198
[714]199        // do not touch these:
200        paInt refno; ///< this joint's reference number
201        double stamina;
202        double stif, rotstif;   ///< stiffness for moving and bending forces
203        class Orient o; ///< orientation delta between parts as rotation matrix
204        /** flag: generated f0 should include delta data.
205                set by 'singlestep' if j: attributes use delta option */
206        bool usedelta;
207        Pt3D vcolor;
[109]208
[899]209        static Param &getStaticParam();
[109]210};
211
212#define JOINT_DELTA_MARKER 99999.0
213
214
[899]215
216////////////////// Neural Network /////////////////
217
[109]218class NeuroClass;
219
[899]220typedef UserTags<NeuroClass, void *, 5> NeuroClassUserTags;
[109]221
222/** Information about neuron class.
223 */
224class NeuroClass
225{
[714]226        bool ownedvectordata;
[899]227        void operator=(const NeuroClass &nosuchthich) {}
[714]228public:
229        SString name, longname, description;
230        ParamEntry *props;
[1280]231        bool ownedprops; //< destructor will free props using ParamObject::freeParamTab
[714]232        paInt prefinputs, prefoutput;
233        paInt preflocation;
[932]234
[999]235        enum PrefLocation { PREFER_UNATTACHED = 0, PREFER_PART = 1, PREFER_JOINT = 2 };
236
237        static constexpr int SUPPORTED_SHAPETYPE_BALL_AND_STICK = 1;
238        static constexpr int SUPPORTED_SHAPETYPE_SOLIDS = 2;
239        static constexpr int SUPPORTED_SHAPETYPE_ALL = SUPPORTED_SHAPETYPE_BALL_AND_STICK | SUPPORTED_SHAPETYPE_SOLIDS;
[932]240        paInt supported_shape_types; //< bitfield of 'Model::shape' values: NeuroClass::SUPPORTED_SHAPE_xxx = 1 << Model::SHAPE_xxx
[975]241
[1004]242        static constexpr int SUPPORTED_JOINT_STICK = 1;
[975]243        static constexpr int SUPPORTED_JOINT_FIXED = 2;
244        static constexpr int SUPPORTED_JOINT_HINGE_X = 4;
245        static constexpr int SUPPORTED_JOINT_HINGE_XY = 8;
[1004]246        static constexpr int SUPPORTED_JOINTSHAPE_ALL = SUPPORTED_JOINT_STICK + SUPPORTED_JOINT_FIXED + SUPPORTED_JOINT_HINGE_X + SUPPORTED_JOINT_HINGE_XY;
[977]247        paInt supported_joint_shapes; //< bitfield of 'Joint::shape' values: NeuroClass::SUPPORTED_JOINT_xxx = 1 << JOINT::SHAPE_xxx
[975]248
[714]249        int *vectordata;
250        paInt visualhints;
[109]251
[714]252        //void *impl;
253        int impl_count;
254        bool active;
255        bool genactive;
256        NeuroClassUserTags userdata;
[109]257
[714]258        //////////////////////
259        ~NeuroClass();
260        NeuroClass();
261        NeuroClass(ParamEntry *_props, SString _description,
[999]262                int _prefinputs, int _prefoutput, int _preflocation, int *_vectordata, bool own_vd = 1, int vhints = 0, int sup_shapes = NeuroClass::SUPPORTED_SHAPETYPE_ALL, int sup_joints = NeuroClass::SUPPORTED_JOINTSHAPE_ALL);
[714]263        /** class name for use in Neuro::setClassName(), Neuro::setDetails() (former 'moredata' field),
264                eg. "N","-",G" */
[899]265        const SString &getName() { return name; }
[714]266        /** human friendly name, eg. "Neuron","Link","Gyroscope"  */
[899]267        const SString &getLongName() { return longname; }
[714]268        /** long description */
[899]269        const SString &getDescription() { return description; }
270        ParamEntry *getParamTab() { return props; }
[109]271
[714]272        /** NeuroClass specific properties, recognized by all neurons of this class */
273        Param getProperties() { return Param(props); }
[109]274
[714]275        /** preferred number of inputs, -1 = no preference (any number will go).
276                extra inputs may be ignored by the object (depends on the class).
277                */
278        int getPreferredInputs() { return (int)prefinputs; }
[109]279
[714]280        /** @return 0 if this object doesn't provide useful output signal. */
281        int getPreferredOutput() { return (int)prefoutput; }
[109]282
[978]283        /** @return 0 (PREFER_UNATTACHED) if the neuron doesn't need any assignment to a body element.
284                @return 1 (PREFER_PART) if the neuron likes to be attached to a Part ( @see Neuro::attachToPart() )
285                @return 2 (PREFER_JOINT) if the neuron prefers to be attached to a Joint ( @see Neuro::attachToJoint() )
[714]286                */
[997]287        PrefLocation getPreferredLocation() { return (PrefLocation)preflocation; }
[714]288        /** vector drawing to be used in neuro net diagram.
289                interpretation:
290                {
291                LEN = datalength (excluding this number)
292                NL = number_of_lines
293                line#1 ->  NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
294                ...
295                line#NL -> NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
296                }
297                */
[932]298        int getSupportedShapeTypes() { return (int)supported_shape_types; }
[934]299        bool isShapeTypeSupported(ModelEnum::ShapeType t) { return (1 << (int)t) & supported_shape_types; }
[977]300        int getSupportedJointShapes() { return (int)supported_joint_shapes; }
301        bool isJointShapeSupported(Joint::Shape t) { return (1 << (int)t) & supported_joint_shapes; }
[899]302        int *getSymbolGlyph()
[714]303        {
304                return vectordata;
305        }
[1280]306        void setSymbolGlyph(int *data, bool owned = true)
[714]307        {
[899]308                if (vectordata && ownedvectordata) delete[]vectordata;
[1280]309                vectordata = data;
310                ownedvectordata = owned;
[714]311        }
312        /** additional information about how the neuron should be drawn
313                used by structure view (and maybe some other components).
314                return value is defined by the enum Hint
315                @see enum Hint
316                */
317        int getVisualHints()
318        {
319                return (int)visualhints;
320        }
[109]321
[714]322        enum Hint
[738]323        {
[714]324                /** don't draw neurons of this class */
325                Invisible = 1,
326                /** don't draw classname label below the neuron */
327                DontShowClass = 2,
328                /** draw the neuron at the first part when attached to joint (default is in the middle) */
329                AtFirstPart = 4,
330                /** draw the neuron at the second part when attached to joint (default is in the middle) */
331                AtSecondPart = 8,
332                /** use effector colour for this neuro unit */
333                EffectorClass = 16,
334                /** use receptor colour for this neuro unit */
335                ReceptorClass = 32,
[937]336                IsV1BendMuscle = 64,
337                IsV1RotMuscle = 128,
338                IsLinearMuscle = 256,
339                IsSolidMuscle = 512
[714]340        };
[109]341
[714]342        /** textual summary, automatically generated from other properties (like the neuro class tooltip) */
343        SString getSummary();
344
345        static void resetActive(); ///< set default values of active and genactive for all classes
[899]346        static void setGenActive(const char *classes[]); ///< set genactive for specified classes
[109]347};
348
349
[899]350
351
352
353
354/** Single processing unit in Framsticks neural network.  */
[714]355class Neuro : public PartBase
[109]356{
[714]357        friend class Model;
358        static SString getDefaultStyle();
[109]359
[714]360        struct NInput {
361                Neuro *n; double weight; SString *info;
362                NInput(Neuro *_n, double w, SString *i = 0) :n(_n), weight(w), info(i) {}
363        };
[109]364
[714]365        SListTempl<NInput> inputs;
[109]366
[714]367        NeuroClass *myclass;
368        bool knownclass;
369        SString myclassname, myclassparams;
370        /** set myclass and make knownclass=true */
371        void checkClass();
[899]372        SString **inputInfo(int i);
[714]373        void defassign();
[109]374
375public:
[714]376        enum NeuroFlags { HoldState = 2 };
377        Param properties();
378        Param extraProperties();
[109]379
[899]380        void setInputInfo(int i, const SString &name, const SString &value);
381        void setInputInfo(int i, const SString &name, int value);
382        void setInputInfo(int i, const SString &name, double value);
[714]383        SString getInputInfo(int i);
[899]384        SString getInputInfo(int i, const SString &name);
[109]385
[899]386        NeuroClass *getClass();
387        void setClass(NeuroClass *);
[109]388
[714]389        SString getClassParams() { return myclassparams; }
[899]390        void setClassParams(const SString &cp) { myclassparams = cp; }
[109]391
[714]392        SString getClassName();
[899]393        void setClassName(const SString &clazz);
[109]394
[714]395        /** return neuro unit details encoded as <CLASS> ":" <PROPERTIES>
[109]396
[714]397                new Neuro can be created as root object (without parent) or can be
398                the child of existing Neuro. Children of the Neuro are its inputs.
399                Standard Framsticks neuron calculates the sum of all input units - other processing
400                units don't have to treat them equally and can even ignore some of them.
401                There are hints about expected inputs in the class database, @see getClass
[109]402
[714]403                Application should not assume anything about classes and its properties
404                except for two standard classes: (information about all current classes
405                can be retrieved with getClass/getClassProperties methods)
406                - getClassName()="N" is the standard Framsticks neuron, accepts any number of inputs,
407                compatible with old Neuro object
408                - getClassName()="-" is the neuron link, compatible with old Neuro-Neuro link
409                (NeuroItem with empty details)
410                Empty details defaults to "-" if the parent unit is specified,
411                and "N" if the unit has no parent.
412                */
413        SString getDetails();
[109]414
[714]415        /** details = classname + ":" + classparams
416                @see getDetails()
417                */
[899]418        void setDetails(const SString &);
[714]419
[109]420#define STATRICKCLASS Neuro
[714]421        PARAMGETDEF(details) { arg1->setString(getDetails()); }
422        PARAMSETDEF(details) { setDetails(arg1->getString()); return PSET_CHANGED; }
423        PARAMGETDEF(inputCount);
424        PARAMPROCDEF(p_getInputNeuroDef);
425        PARAMPROCDEF(p_getInputNeuroIndex);
426        PARAMPROCDEF(p_getInputWeight);
427        PARAMGETDEF(classObject);
[109]428#undef STATRICKCLASS
429
[714]430        ///@param handle_defaults_when_saving see SyntParam
431        SyntParam classProperties(bool handle_defaults_when_saving = true);
432        // base properties:
433        paInt refno; ///< unique reference number (former 'neuro' refno)
[109]434
[714]435        paInt part_refno; ///< can be used by some items as the part ref#
436        paInt joint_refno; ///< can be used by some items as the joint ref#
[109]437
[714]438        Pt3D pos, rot;  ///< default = zero
[109]439
[714]440        ModelUserTags userdata;
[109]441
[714]442        Neuro();
443        Neuro(double _state, double _inertia, double _force, double _sigmo);
[899]444        Neuro(const Neuro &src) :PartBase(getDefaultStyle()) { operator=(src); }
[109]445
[714]446        ~Neuro();
[109]447
[899]448        void operator=(const Neuro &src);
[109]449
[714]450        /** Attach this Neuro to the specified Part or detach it from the body if p==NULL.
451                Neuro can be attached to either Part or Joint, but not both.
452                @see getPart()
453                */
[899]454        void attachToPart(Part *p) { part = p; joint = 0; }
[109]455
[714]456        /** Attach this Neuro to the specified Joint or detach it from the body if p==NULL.
457                Neuro can be attached to either Part or Joint, but not both.
458                @see getJoint()
459                */
[899]460        void attachToJoint(Joint *j) { joint = j; part = 0; }
[109]461
[714]462        void attachToPart(int i);
463        void attachToJoint(int i);
[109]464
[714]465        /** @return Part the Neuro is attached to, or NULL if it has no defined location on the body.
466                @see attachToPart()
467                */
468        Part *getPart() { return part; }
[109]469
[714]470        /** @return Joint the Neuro is attached to, or NULL if it has no defined location on the body.
471                @see attachToJoint()
472                */
473        Joint *getJoint() { return joint; }
[109]474
[714]475        int isOldEffector();
476        int isOldReceptor();
477        int isOldNeuron();
478        int isNNConnection();
[109]479
[714]480        /** @return the number of inputs connected to this Neuro.
481                Functions like getInput(), getInputWeight() will accept connection number [0..InputCount-1]
482                */
483        int getInputCount() const { return inputs.size(); }
[109]484
[714]485        /// @return the number of output connections (including possible self-connections)
486        int getOutputsCount() const;
[109]487
[714]488        /** @return the Neuro connected as i-th input */
[899]489        Neuro *getInput(int i) const { return (i >= inputs.size()) ? 0 : inputs(i).n; }
[714]490        /** @return the Neuro connected as i-th input.
491                @param weight
492                */
[899]493        Neuro *getInput(int i, double &weight) const;
[714]494        /** @return connectin weight for i-th input */
495        double getInputWeight(int i) const;
496        /** change connection weight for i-th input */
497        void setInputWeight(int i, double weight);
498        /** connect i-th input with another neuron */
[899]499        void setInput(int i, Neuro *n);
[714]500        /** connect i-th input with another neuron */
[899]501        void setInput(int i, Neuro *n, double weight);
[714]502        /** add new input. @return its reference number */
[899]503        int addInput(Neuro *child, double weight = 1.0, const SString *info = 0);
[714]504        /** @return reference number [0..InputCount-1] of the input
505           or -1 if 'child' is not connected with this Neuro.*/
[899]506        int findInput(Neuro *child) const;
[714]507        void removeInput(paInt refno);
508        /**    @return reference number of the child connection, like findInput() */
[899]509        int removeInput(Neuro *child);
[109]510
[899]511        int findInputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
512        int findOutputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
[109]513
[714]514        /* class database retrieval */
515        static int getClassCount();
516        /** @return Neuro class name.
517                @param classindex 0 .. getClassCount()
518                */
519        static SString getClassName(int classindex);
[899]520        static NeuroClass *getClass(int classindex);
521        static NeuroClass *getClass(const SString &classname);
522        static int getClassIndex(const NeuroClass *nc);
[109]523
[714]524        // not really private, but you should not access those directly
525        double state;
[109]526
[714]527        /** may reference parent neuron if parentcount is exacty 1. parent is invalid otherwise. @sa parentcount */
528        Neuro *parent;
529        int parentcount; ///< @sa parent
[109]530
[714]531        Part *part;     ///< link to the Part
532        Joint *joint;   ///< link to the Joint - required by some objects (eg.muscles)
533        Orient o;       ///< rotation matrix calculated from "rot"
534        static ParamEntry emptyParamTab[];
[899]535        static Param &getStaticParam();
[109]536};
537
[714]538class NeuroExt : public Neuro
[109]539{
[714]540public:
[109]541#define STATRICKCLASS NeuroExt
[714]542        PARAMGETDEF(neuroclass);
543        PARAMSETDEF(neuroclass);
[952]544        PARAMGETDEF(liveNeuro);
[109]545#undef STATRICKCLASS
[714]546        static ParamEntry *getParamTab();
[109]547};
548
549class NeuroConn
550{
[714]551        void defassign();
552public:
553        int n1_refno, n2_refno;
554        double weight;
555        SString info;
556        NeuroConn();
[109]557};
558
[934]559extern ParamEntry f0_part_paramtab[], f0_part_minmaxdef_paramtab[], f0_joint_paramtab[], f0_nodeltajoint_paramtab[], f0_neuro_paramtab[], f0_neuroconn_paramtab[], f0_neuroitem_paramtab[];
[109]560
561#endif
Note: See TracBrowser for help on using the repository browser.