.\" @(#)code	1.8 12/8/92
.H1 "Writing C++ code for stars"
.pp
This section assumes a knowledge of the C++ language; no attempt
will be made to teach the language.  We recommend ``C++ Primer'',
by Stanley Lippman (from Prentice-Hall) for those new to the
language.
.IE C++ Primer
.pp
C++ code segments are an important part of any star definition.
They can appear in the
.c setup ,
.c go ,
.c wrapup ,
.c constructor ,
.c destructor ,
.c exectime ,
.c code ,
and
.c method
directives in the \*(PT preprocessor.
These directives all include a body of arbitrary C++ code, enclosed
by curly braces, ``{'' and ``}''.
In all but the
.c code
directive, the C++ code between braces
defines the body of a method
.IE method
of the star class.  This method can access any member of the class,
.IE member
including portholes (for input and output), states, and members
defined with the
.c public ,
.c protected ,
and
.c private
directives.
.H2 "The structure of a Ptolemy star"
.pp
In general, the task of a Ptolemy star is to receive input Particles
and/or produce output Particles; in addition, there may be side effects
(reading or writing files; displaying graphs).  As for all C++ objects,
the constructor is called when the object is created, and the destructor
is called when the object is destroyed.  In addition, the setup() method,
if any, is called every time a new simulation run is started, the go()
method (which always exists except for stars like BlackHole and Null
that do nothing) is called each time a star is to be executed, and
the wrapup() method is called to complete the simulation run.
.H2 "Reading inputs and writing outputs"
.pp
The precise mechanism for references to input and output portholes
depends somewhat on the domain.  This is because stars in the domain
XXX use objects of class InXXXPort and OutXXXPort (derived from PortHole)
for input and output, respectively.
We will explain here how such references are used in the SDF domain.
A later section discusses the DE domain.
For information about other domains, please see the domain document in
the Almagest.
.H3 "PortHoles and Particles"
.pp
In the SDF domain, normal
inputs and outputs become members of type
.c InSDFPort
and
.c OutSDFPort
after the preprocessor is finished.
.IE InSDFPort
.IE OutSDFPort
These are derived from base class
.c PortHole .
.IE PortHole
For example, given the following directive in the
.c defstar
of an SDF star,
.(c
	input {
		name {in}
		type {float}
	}
.)c
a member named
.c in ,
of type
.c InSDFPort ,
will become part of the star.
.pp
We are not usually interested in directly accessing these porthole classes,
but rather wish to read or write data through the portholes.
All data passing through a porthole is derived
from base class
.c Particle .
.IE Particle
Each particle contains data of the type specified in the
.c type
subdirective of the
.c input
or
.c output
directive.
Currently this can be float, int, complex, or ``message''.
.pp
The operator ``%'' operating on an SDF porthole returns a reference
to a particle.
Consider the following example:
.(c
go {
	Particle& currentSample = in%0;
	Particle& pastSample = in%1;
	...
}
.)c
The right-hand argument to the ``%'' operator specifies the delay
of the access.  A zero always means the most recent particle.
A one means the particle arriving just before the most recent particle.
The same rules apply to outputs.  Given an output named ``out'',
the same particles that are read from ``in'' can be written to
``out'' in the same order as follows:
.(c
go {
	...
	out%1 = pastSample;
	out%0 = currentSample;
}
.)c
This works because
.c out%n
returns a \fIreference\fR to a particle, and hence
can accept an assignment.
The assignment operator for the class
.c Particle
is overloaded to make a copy of the data field of the particle.
.pp
Operating directly on class
.c Particle ,
as in the above examples, is useful for writing stars that accept
ANYTYPE of input.  The operations need not concern themselves
with the type of data contained by the particle.
But it is far more common to operate numerically on the data
carried by a particle.
This can be done using a cast to a compatible type.
For example, since ``in'' above is of type
.c float ,
its data can be accessed as follows:
.(c
go {
	Particle& currentSample = in%0;
	double value = double(currentSample);
	...
}
.)c
or more concisely,
.(c
go {
	double value = double(in%0);
	...
}
.)c
The expression
.c double(in%0)
can be used anywhere that a double can be used.  In many contexts,
where there is no ambiguity, the conversion operator can be omitted:
.(c
	double value = in%0;
.)c
However, since conversion operators are defined to convert Particles
to several types, it is often necessary to indicate precisely which
type conversion is desired.
.pp
To write data to an output porthole, note that the right-hand
side of the assignment operator should be of type
.c Particle ,
as shown in the above example.
An operator ``<<'' is defined for particle classes to make
this more convenient.
Consider the following example:
.(c
go {
	float t;
	t = \fIsome value to be sent to the output\fP
	out%0 << t;
}
.)c
Note the distinction between the ``<<'' operator and the assignment
operator; the latter operator copies Particles, the former operator
loads data into particles.  The type of the right-side operand
of ``<<'' may be
.c int ,
.c float ,
.c double ,
.c Complex
or
.c Envelope;
the appropriate type conversion will be performed.
For more information on the
.c Envelope
and
.c Message
types, please see the appendix at the end of this section.
.H3 "SDF PortHole parameters"
.pp
In the above example, where
.c in%1
was referenced,
some special action is required to tell \*(PT that past input
particles are to be saved.
Special action is also required to tell the SDF scheduler how
many particles will be consumed at each input and produced
at each output when a star fires.  This information can be
provided through a call to
.c setSDFParams
in the
.c setup
method.
.IE setSDFParams
.IE "SDF parameters"
.IE "past particles"
.IE "consuming multiple particles"
.IE "producing multiple particles"
This has the syntax
.(c
setup {
	\fIname\fP.setSDFParams(\fImultiplicity, past\fP)
}
.)c
where \fIname\fP is the name of the input or output porthole,
\fImultiplicity\fP is the number of particles consumed or produced,
and \fIpast\fP is the number of past samples accessed.
For the above example, \fIpast\fP would have to be at least one.
.H3 "Multiple PortHoles"
.pp
.IE "multiple portholes"
Sometimes a star should be defined with
.i n
input portholes or
.i n
output portholes, where
.i n
is variable.
This is supported by the class
.c MultiPortHole
.IE MultiPortHole
and its derived classes.
An object of this class is a sequential list of
.c PortHole s.
For SDF, we have the specialized derived class
.c MultiInSDFPort
(which contains
.c InSDFPorts )
and
.c MultiOutSDFPort
(which contains
.c OutSDFPorts ).
.pp
Defining a multiple porthole is easy, as illustrated below:
.(c
defstar {
	...
	inmulti {
		name {\fIinput_name\fP}
		type {\fIinput_type\fP}
	}
	outmulti {
		name {\fIoutput_name\fP}
		type {\fIoutput_type\fP}
	}
}
.)c
.IE inmulti
.IE outmulti
.pp
To successively access individual portholes in a
.c MultiPortHole ,
the
.c MPHIter
iterator class should be used.
.IE iterators
.IE MPHIter
.IE "MuliPortHole iterator"
Consider the following example:
.(c
defstar {
	name {Fork}
	domain {SDF}
	desc { Copies input particles to each output. }
	input {
		name{input}
		type{ANYTYPE}
	}
	outmulti {
		name{output}
		type{= input}
	}
	go {
		MPHIter nextp(output);
		PortHole* p;
		while ((p = nextp++) != 0)
			(*p)%0 = input%0;
	}
}
.)c
A single input porthole supplies a particle that gets copied
to any number of output portholes.
The
.c type
of the
.c output
.c MultiPortHole
is inherited from the type of the input.
The first line of the
.c go
method creates an
.c MPHIter
iterator called
.c nextp ,
initialized to point to portholes in
.c output .
The ``++'' operator on the iterator returns a pointer to the next porthole
in the list, until there are no more portholes, at which time it
returns zero.
So the
.c while
construct steps through all output portholes, copying the input
particle data to each one.
.pp
Consider another example, which sums any number of inputs:
.(c
defstar {
	name {Add}
	domain {SDF}
	desc { Output the sum of the inputs, as a floating value.  }
	inmulti {
		name {input}
		type {float}
	}
	output {
		name {output}
		type {float}
	}
	go {
		MPHIter nexti(input);
		PortHole *p;
		double sum = 0.0;
		while ((p = nexti++) != 0)
			sum += double((*p)%0);
		output%0 << sum;
	}
}
.)c
Again, an
.c MPHIter
iterator named
.c nexti
is created and used to access the inputs.
.pp
Upon occation, the
.c numberPorts()
method of class
.c MultiPortHole ,
which returns the number of ports, is useful.
.H3 "Type conversion"
.pp
.IE "Particle types"
.IE types
The type conversion operators and ``<<'' operators are defined
as virtual methods in the base class
.c Particle .
There are never really objects of class
.c Particle
in the system; instead, there are objects of class
.c IntParticle ,
.c FloatParticle ,
.c ComplexParticle ,
which hold data of type
.c int ,
.c double
(not float!),
and
.c Complex ,
respectively (there is also
.c MessageParticle ,
which is described later).  The conversion and loading operators are designed
to ``do the right thing'' when an attempt is made to convert
between mismatched types.
.pp
Clearly we can convert an
.c int
to a
.c double
or
.c Complex ,
or a
.c double
to a
.c Complex ,
with no loss of information.  Attempts to convert in the opposite
direction work as follows: conversion of a
.c Complex
to a
.c double
produces the magnitude of the complex number.
Conversion of a
.c double
to an
.c int
produces the greatest integer that is less than or equal to
the
.c double
value.  There are also operators to convert to or from
.c float .
.pp
This gives considerable flexibility in defining code that
operates on ANYTYPE.
For instance, since ANYTYPE of particle can be cast to double,
a plotting star can accept ANYTYPE of input, and internally
the star only has to cast the input to double.
Of course, if the input is complex, some information is lost;
thus when complex values are fed directly to the Xgraph star,
the magnitudes of the values are plotted.
.pp
Each particle also has a virtual
.c print()
method, so a star that writes particles to a file can
also accept ANYTYPE.
.H3 "PortHoles in the DE domain"
.pp
For convenience, we give here a brief description of how data
is accessed in the DE domain.  More details are given in the DE domain
section of the Almagest.
.pp
In the DE domain, there is a time associated with each event;
.IE "DE timestamps"
this time is set in the star's
.c arrivalTime
member.
When a star's
.c go()
function is called, the
.c arrivalTime
.IE arrivalTime
member
contains the current time.  If there is only one input
.c DEPortHole ,
then it is guaranteed that there is a Particle in that
.c DEPortHole .
.IE DEPortHole
If the star has more than one input porthole, then you must
poll to find out which porthole has new data; that is done by
checking the
.c dataNew
.IE dataNew
member of the
.c DEPortHole .
It is possible
for simultaneous events to arrive on several different input portholes.
However, if simultaneous events arrive on the same input porthole, the
scheduler fires the star two separate times, presenting the
events one at a time.  The result is that any input porthole
has at most one event (particle).
.pp
For convenience a
.c completionTime
.IE completionTime
data member is provided in
.c DEStar s,
but the user need not use it; it is initialized to zero at the
start of execution.  By convention,
.c completionTime
is used
to compute the timestamp to be used for output particles; doing
this in a data member allows it to be remembered across executions.
However, the star writer is not required to use
.c completionTime
at all.
.pp
Particles may be read from
.c DEPortHole s
either by using
.c input%0
as for other types of portholes, or by using the
.c get()
method.
.c  input.get()
is identical to
.c input%0
except that the
.c dataNew
flag of input is cleared as well.
To write Particles to output DEPortHoles, the
.c put(double)
method is used.  The argument to
.c put
is a timestamp value, and it returns a
reference to a Particle; you may copy another Particle to this reference
or load data into it.  For example:
.(c
	output.put(completionTime) = input.get();

	output.put(completionTime) << dataValue;
.)c
If a particle arrives on an input and you do not
.c get()
it, it is discarded; it is not queued (to implement a queue, the
.c Queue
class defined in
.c DataStruct.h
may be used).  In many cases an input signal is used
for timing control (as a clock input) and you don't care about the
data value at all; in that case, code typically just resets the
.c dataNew
flag of the porthole.
A
.c DEStar
must have at least one input porthole to work correctly.
How, then, are source stars defined?  They are produced by deriving
from class
.c DERepeatStar .
.IE DERepeatStar
A
.c DERepeatStar
has a hidden pair of portholes
that form a feedback loop, but this is hidden from you and you don't
need to worry about it.  A
.c DERepeatStar
is always fired at time zero,
and the method
.c refireAtTime(double)
is provided; this allows the star
to schedule itself for later execution.  In many cases it is convenient
to schedule the first execution at time zero; think of this as actually
occurring at time epsilon for a very small epsilon.  If a
.c DERepeatStar
defines a setup function, that function must call
.c DERepeatStar::setup() .
.pp
Here is a (simplified) version of DEClock, which outputs a zero-valued
token every 5 time units (the real star is parametized):
.(c
go {
	output.put(completionTime) << 0.0;
	refireAtTime(completionTime);
	completionTime += 5.0;
}
.)c
Notice that there are two firings at time zero; the first produces
a token at time zero, the second at time 5.0.
.pp
When MultiPortHoles are used, we can't just use an
.c MPHIter
because
it returns a pointer to class
.c PortHole
and we need to use
.c DEPortHole
specific methods.  To handle this, two additional iterator classes are
provided:
.c OutDEMPHIter ,
for output multiportholes, and
.c InDEMPHIter ,
.IE OutDEMPHIter
.IE InDEMPHIter
.IE InDEPort
.IE OutDEPort
for input multiportholes.  The former returns a pointer to
.c OutDEPort
on each execution, and the latter returns a pointer to 
.c InDEPort
on each execution.
.pp
Here is the
.c go()
function from
.c DEFork :
.(c
go {
	completionTime = arrivalTime;
	Particle& pp = input.get();
	OutDEMPHIter nextp(output);
	OutDEPort *oport;
	while ((oport = nextp++) != 0)
		oport->put(completionTime) = pp;
}
.)c
Here is the go() function from
.c DEMerge .
Here, we use the dataNew flag
to see which input(s) contain(s) new data:
.(c
go {
	completionTime = arrivalTime;
	InDEMPHIter nextp(input);
	InDEPort* iport;
	while ((iport = nextp++) != 0) {
		if (iport->dataNew)
			output.put(completionTime) = iport->get();
	}
}
.)c
.H2 "States"
.pp
This section is not domain-specific; states are the same in any
domain.
.IE "state"
.IE "attributes"
A state is defined by the
.c defstate
directive.
The star can use a state to store data values, remembering
them from one invocation to another.  They differ from ordinary
members of the star, which are defined using the
.c public ,
.c protected ,
and
.c private
directives, in that they have a name, and can be accessed from
outside the star in systematic ways.  For instance, the graphical
interface Pigi permits the user to set any state with the A_SETTABLE
attribute to some value prior to a run, using the \fIedit-params\fR command.
The interpreter provides similar functionality through the
.c setstate
command.
The state attributes are set in the
.c defstate
directive.
A state may be modified by the star code during a run.
The attribute A_NONCONSTANT is used
.IE A_SETTABLE
.IE A_NONCONSTANT
as a pragma to mark a state as one that gets modified during
a run.
There is currently no mechanism for checking the correctness of these
attributes.
.pp
All states are derived from the base class
.c State ,
defined in the \*(PT kernel.
The derived state classes currently defined in the kernel are
.c FloatState ,
.c IntState ,
.c ComplexState ,
.c StringState ,
.c FloatArrayState ,
.c IntArrayState ,
.c ComplexArrayState ,
and
.c StringArrayState .
.pp
A state can be used in a star method
just like the corresponding predefined data types.
As an example, suppose the star definition contains the following directive:
.(c
defstate {
	name { myState }
	type { float }
	default { 1.0 }
	descriptor { Gain parameter. }
}
.)c
This will define a member of class
.c FloatState
with default value 1.0.
.IE FloatState
No attributes are defined, so A_CONSTANT and A_SETTABLE, the default
attributes, are assumed.
To use the value of a state, it should be cast to type
.c double ,
either explicitly by the programmer or implicitly by the context.
For example, the value of this state can be accessed in the
.c go
method as follows:
.(c
go {
	output%0 << myState * double(input%0);
}
.)c
The references to input and output are explained above.
The reference to
.c myState
works because an unambiguous cast to
.c double
is defined in
.c FloatState
class, and it is automatically invoked by the C++ compiler.
(Similarly, a cast to
.c int
is defined for
.c IntState ,
to
.c Complex
from
.c ComplexState ,
.IE ComplexState
and to
.c char*
for
.c Stringstate ).
.IE IntState
.IE StringState
.pp
Note that the type
.c Complex
.IE "Complex type"
is not a fundamental part of C++.
We have implemented a subset of the
.c Complex
class as defined by several library vendors; we use our own version
for maximum portability.
Using the
.c ComplexState
class will automatically ensure the inclusion of the appropriate header
files.
A member of the
.c Complex
class can be initialized and operated upon any number of ways.
For details, see the file ~ptolemy/src/kernel/ComplexSubset.h.
.pp
A state may be updated by ordinary assignment in C++, as in the following
lines
.(c
	double t;
	t = \fIsome value\fP;
	myState = t;
.)c
This works because the
.c FloatState
class definition has overloaded the assignment operator (``='')
to set its value from a double.
Similarly, an
.c IntState
can be set from an
.c int
and a
.c StringState
can be set from a
.c char*
or
.c "const char*" .
.H2 "Array States"
.pp
The
.c ArrayState
.IE ArrayState
.c class es
(
.c FloatArrayState ,
.c IntArrayState
and
.c ComplexArrayState )
.IE FloatArrayState
.IE IntArrayState
.IE ComplexArrayState
are used to store arrays of data.
For example,
.(c
defstate {
	name { taps }
	type { FloatArray }
	default { "0.0 0.0 0.0 0.0" }
	descriptor { An array of length four. }
}
.)c
defines an array of type
.c double
with dimension four, with each element initialized to zero.
Quotes must surround the initial values.
Alternatively, you can specify a file name with a prefix 
.c "<".
.IE "initializing states from files"
If you have a file named "foo" that contains the default values for
an array state,
you can write,
.(c
	default { "< foo" }
.)c
The format of the file is also a  sequence of data separated by spaces
(or newlines, tabs, or commas).
File input can be combined with direct data input as in
.(c
	default { "<foo 2.0" }
	default { "0.5 <foo <bar" }
.)c
.pp
A "repeat" notation is also supported for
.c ArrayState
objects: the two value strings
.(c
	default { "1.0 [5]" }
	default { "1.0 1.0 1.0 1.0 1.0" }
.)c
are equivalent.  Any integer expression may appear inside the braces.
.pp
The number of elements in an
.c ArrayState
can be determined by calling its
.c size()
method.
The size is not specified explicitly, but is calculated by scanning
the default value.
.pp
As an example of how to access the elements of an
.c ArrayState ,
suppose
.c fState
is a
.c FloatState
and
.c aState
is a
.c FloatArrayState .
The accesses, like those in the following lines, are routine:
.(c
sState = aState[1] + 0.5;
aState[1] = (double)sState * 10.0;
aState[0] = sState * aState[2];
.)c
.pp
For a more complete example of the use of 
.c FloatArrayState ,
consider the class 
.c FIR
defined below.
Note that this is a simplified version of the SDF
.c FIR
star that does not permit interpolation or decimation.
.(c
defstar {
	name {FIR}
	domain {SDF}
	desc {
A Finite Impulse Response (FIR) filter.
	}
	version {@(#)code	1.8 12/8/92}
	author { E. A. Lee }
	input {
		name {signalIn}
		type {float}
	}
	output {
		name {signalOut}
		type {float}
	}
	defstate {
		name {taps}
		type {floatarray}
		default {
	"-.040609 -.001628 .17853 .37665 .37665 .17853 -.001628 -.040609"
		}
		desc { Filter tap values. }
	}
	setup {
		// tell the PortHole the maximum delay we will use
		signalIn.setSDFParams(1, taps.size() - 1);
	}
	go {
		double out = 0.0;
		for (int i = 0; i < taps.size(); i++)
			out += taps[i] * double(signalIn%i);
		signalOut%0 << out;
	}
}
.)c
.pp
Notice the
.c setup
method; this is necessary to allocate a buffer in the input
.c PortHole
large enough to hold the particles that are accessed in the
.c go()
method.
Notice the use of the
.c size()
method of the
.c FloatArrayState.
.pp
We now illustrate an interpreter session using the above
.c FIR
.c Star .
Assume there is a galaxy called
.c SinGen
that generates a sine wave.
you can use it with the
.c FIR
.c star,
as in:
.(c
galaxy foop SinGen
star fir FIR
star printer Printer
connect foop output fir signalIn
connect fir signalOut printer input
print fir
Star: mainGalaxy.fir
	...
States in the star fir:
mainGalaxy.fir.taps type: FloatArray
 initial value: -.040609 -.001628 .17853 .37665 .37665 .17853 -.001628 -.040609
 current value:
0 -0.040609
1 -0.001628
2 .17853
3 .37665
4 .37665
5 .17853
6 -0.001628
7 -0.040609
.)c
Then you can re-define taps by reading them from a file "foo", which
contains the data:
.(c
1.1
-2.2
3.3
-4.4
.)c
The resulting interpreter commands are:
.(c
setstate fir taps "<foo 5.5"
print fir
Star: mainGalaxy.fir
	...
States in the star fir:
mainGalaxy.fir.taps type: FloatArray
 initial value: <foo 5.5
 current value:
0 1.1
1 -2.2
2 3.3
3 -4.4
4 5.5
PTOLEMY:
.)c
This illustrates that \fIboth\fR the contents and the size of a
.c FloatArrayState
are changed by a
.c setstate
command.  Also, notice that file values may be combined with
string values; when
.(c
< filename
.)c
occurs in an
.i initial-value ,
it is processed exactly as if the whole file were substituted at
that point.
.H3 "Modifying states in derived classes"
.pp
When one star is derived from another, it inherits all the states
of the baseclass star.  Sometimes we want to modify some aspect
of the behavior of a baseclass state in the derived class.  This
is done by placing calls to member functions of the state in the
constructor of the derived star.  Useful functions include
.c setInitValue
to change the default value, and
.c setAttibututes
and
.c clearAttributes
to modify attributes.
.H2 "Using random numbers"
.pp
Ptolemy uses the GNU library routines for the random number generation.
Refer to Volume II of the Art of Computer Programming
by Knuth for details about the method.  There are built-in classes
for some popular distributions: uniform, exponential, geometric, 
discrete uniform, normal, log-normal, and so on.  These classes use a
common basic random number generation routine which is realized in the
\fBACG\fR class.  Here are some examples of using random numbers.
.pp
The first example is the part of the DE Poisson star preprocessor file.
.(c        
        hinclude { <NegExp.h> }
        ccinclude { <ACG.h> }
        protected {
                NegativeExpntl *random;
        }
// declare the static random-number generator in the .cc file
        code {
                extern ACG* gen;
        }
        constructor {
                random = NULL;
        }
        destructor {
                if(random) delete random;
        }
        setup {
                if(random) delete random;
                random = new NegativeExpntl(double(meanTime),gen);
                DERepeatStar :: setup();
        }
        go {
	   ......
           // Generate an exponential random variable.
           double p = (*random)();
	   ......
	}
.)c
The built-in class for an exponentially distributed random numbers is
\fBNegativeExpntl\fR.
.pp
The Ptolemy kernel provides a single object to generate a stream of
random numbers; the global variable
.i gen
(a poor choice of name, perhaps, but it's there now) is a pointer to it.
We define a member of \fBNegativeExpntl\fR class and create
an instance in the \fBsetup()\fR
method, not in the constructor since Ptolemy allows you to change the
seed of the random number.  When the user changes the seed of the
random number generator, the object pointed to by
.i gen
is deleted and re-created, so all objects such as the one pointed
to by
.i random
in this star become invalid.
.pp
Finally, we can read a random number of the specific type by calling 
operator \fB()\fR of the \fBNegativeExpnl\fR class.
.pp
This example uses a uniformly distributed random number.
.(c
        hinclude { <Uniform.h> }
        ccinclude { <ACG.h> }
        protected {
                Uniform *random;
        }
// declare the extern random-number generator in the .cc file
        code {
                extern ACG* gen;
        }
        constructor {
                random = NULL;
        }
        destructor {
                if(random) delete random;
        }
        setup {
                if(random) delete random;
                random = new Uniform(0,double(output.numberPorts()),gen);
        }

        go {
           ......
           double p = (*random)();
	   ......
	}
.)c
You may notice that the two examples above are very similar in nature.
You can get another kind of distribution for the random numbers, by including
the appropriate library file in .h file and by creating the instance
with the right parameters in the \fBsetup()\fR method.
.H2 "Programming examples"
.pp
The following star has no inputs, just an output.
It generates a linearly increasing or decreasing sequence
of float particles on its output:
.(c
defstar {
	name { FloatRamp }
	domain { SDF }
	desc {
Generates a ramp signal, starting at "value" (default 0)
with step size "step" (default 1).
	}
	output {
		name { output }
		type { float }
	}
	defstate {
		name { step }
		type { float }
		default { 1.0 }
		desc { Increment from one sample to the next. }
	}
	defstate {
		name { value }
		type { float }
		default { 0.0 }
		desc { Initial (or latest) value output by Ramp. }
		attributes { A_SETTABLE|A_NONCONSTANT }
	}
	go {
		double t = value;
		output%0 << t;
		t += step;
		value = t;
	}
}
.)c
The state
.c value
is initialized to define the value of the first output.
Each time the star
.c go()
method fires, the
.c value
state is updated to store the next output value.
.pp
The next example multiplies its input by a constant:
.(c
defstar {
	name { FloatGain }
	domain { SDF }
	desc { Amplifier: output is input times "gain" (default 1.0). }
	input {
		name { input }
		type { float }
	}
	output {
		name { output }
		type { float }
	}
	defstate {
		name { gain }
		type { float }
		default { "1.0" }
		desc { Gain of the star. }
	}
	go {
		output%0 << double(gain) * double(input%0);
	}
}
.)c
.pp
The following example illustrates multiple inputs,
ANYTYPE inputs, and the use of the
.c print()
method
of the
.c Particle
class.
.(c
defstar {
	name { Printer }
	domain { SDF }
	desc {
Prints out one sample from each input port per line
If "fileName" is not equal to "cout" (the default), it
specifies the filename to write to.
	}
	explanation {
This star prints its input, which may be any supported type.
There may be multiple inputs: all inputs are printed together on
the same line, separated by tabs.
	}
	inmulti {
		name { input }
		type { ANYTYPE }
	}
	defstate {
		name { fileName }
		type { string }
		default { "cout" }
		desc { Filename for output. }
	}
	protected {
		UserOutput output;
	}
	setup {
		output.fileName(fileName);
	}

	go {
		MPHIter nexti(input);
		PortHole* p;
		while ((p = nexti++) != 0)
		 	output << ((*p)%0).print() << "\t";
		output << "\n";
	}
}
.)c
This star is \fIpolymorphic\fR
.IE polymorphism
since it can operate on any type of input.
Note that the default value of the output filename is ``cout'',
which causes the output to go to the standard output.
