@ -86,7 +86,7 @@ The phase-aligned formant (PAF) synthesis algorithm.</CAPTION>
Example F12.paf.pd (Figure <AHREF="#fig06.17">6.18</A>) is a realization of the PAF generator,
described in Section <AHREF="node96.html#sect6.paf">6.4</A>.
The control inputs specify the fundamental frequency, the center frequency, and
the bandwidth, all in ``MIDI" units. The first steps taken in the realization
the bandwidth, all in "MIDI" units. The first steps taken in the realization
are to divide center frequency by fundamental (to get the center frequency quotient)
and bandwidth by fundamental to get the index of modulation for the
waveshaper. The center frequency quotient is sampled-and-held so that it is
@ -95,7 +95,7 @@ only updated at periods of the fundamental.
<P>
The one oscillator (the <TT>phasor~</TT> object) runs at the fundamental
frequency. This is used both to control a <TT>samphold~</TT> object which
synchronizes updates to the center frequency quotient (labeled ``C.F. relative
synchronizes updates to the center frequency quotient (labeled "C.F. relative
to fundamental" in the figure), and to compute phases for both <TT>cos~</TT> objects which operate as shown earlier in Figure <AHREF="node100.html#fig06.16">6.17</A>.
<P>
@ -115,7 +115,7 @@ The amplitude of the half-sinusoid is then adjusted by an index of modulation
WIDTH="38" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
SRC="img588.png"
ALT="${\omega_b}/\omega$">). The table
(``bell-curve") holds an unnormalized Gaussian curve sampled
("bell-curve") holds an unnormalized Gaussian curve sampled
from -4 to 4 over 200 points (25 points per unit), so the center of the table,
at point 100, corresponds to the central peak of the bell curve. Outside the
interval from -4 to 4 the Gaussian curve is negligibly small.
@ -145,31 +145,31 @@ Filling in the wavetable for Figure <A HREF="#fig06.17">6.18</A>.</CAPTION>
WIDTH="57" HEIGHT="41" ALIGN="MIDDLE" BORDER="0"
SRC="img623.png"
ALT="\fbox{ $\mathrm{until}$\ }"> :
<ANAME="7054"></A>When the left, ``start" inlet is banged, output sequential bangs (with no
elapsed time between them) iteratively, until the right, ``stop" inlet is
banged. The stopping ``bang" message must originate somehow from the
<TT>until</TT> object's outlet; otherwise, the outlet will send ``bang" messages
<ANAME="7054"></A>When the left, "start" inlet is banged, output sequential bangs (with no
elapsed time between them) iteratively, until the right, "stop" inlet is
banged. The stopping "bang" message must originate somehow from the
<TT>until</TT> object's outlet; otherwise, the outlet will send "bang" messages
forever, freezing out any other object which could break the loop.
<P>
As used here, a loop driven by an <TT>until</TT> object
counts from 0 to 199, inclusive. The loop count is maintained by the
``<TT>f</TT>" and ``<TT>+ 1</TT>" objects, each of which feeds the other. But
since the ``<TT>+ 1</TT>" object's output goes to the right inlet of the
``<TT>f</TT>", its result (one greater) will only emerge from the
``<TT>f</TT>" the next time it is banged by ``<TT>until</TT>". So each bang
from ``<TT>until</TT>" increments the value by one.
"<TT>f</TT>" and "<TT>+ 1</TT>" objects, each of which feeds the other. But
since the "<TT>+ 1</TT>" object's output goes to the right inlet of the
"<TT>f</TT>", its result (one greater) will only emerge from the
"<TT>f</TT>" the next time it is banged by "<TT>until</TT>". So each bang
from "<TT>until</TT>" increments the value by one.
<P>
The order in which the loop is started matters: the upper ``<TT>t b b</TT>"
object (short for ``trigger bang bang") must first send zero to the
``<TT>f</TT>", thus initializing it, and then set the <TT>until</TT> object sending
The order in which the loop is started matters: the upper "<TT>t b b</TT>"
object (short for "trigger bang bang") must first send zero to the
"<TT>f</TT>", thus initializing it, and then set the <TT>until</TT> object sending
bangs, incrementing the value, until stopped. To stop it when the value
reaches 199, a <TT>select</TT> object checks the value and, when it sees the
match, bangs the ``stop" inlet of the <TT>until</TT> object.
match, bangs the "stop" inlet of the <TT>until</TT> object.
<P>
Meanwhile, for every number from 0 to 199 that comes out of the ``<TT>f</TT>"
Meanwhile, for every number from 0 to 199 that comes out of the "<TT>f</TT>"
object, we create an ordered pair of messages to the <TT>tabwrite</TT> object.
First, at right, goes the index itself, from 0 to 199. Then for the left inlet,
the first <TT>expr</TT> object adjusts the index to range from -4 to 4 (it
@ -117,12 +117,12 @@ you can send messages to select which table to use.
<ANAME="2556"></A>record an audio signal into a wavetable. In this example the
<TT>tabwrite~</TT> is used to display the output (although later
on it will be used for all sorts of other things.) Whenever it receives a
``bang" message from the pushbutton icon above it, <TT>tabwrite~</TT> begins
"bang" message from the pushbutton icon above it, <TT>tabwrite~</TT> begins
writing successive samples of its input to the named table.
<P>
Example B03.tabread4.pd shows how to combine a <TT>phasor~</TT> and a <TT>tabread4~</TT> object to make a wavetable oscillator. The <TT>phasor~</TT>'s output ranges from
0 to 1 in value. In this case the input wavetable, named ``waveform12", is 131
0 to 1 in value. In this case the input wavetable, named "waveform12", is 131
elements long. The domain for the <TT>tabread4~</TT> object is thus from 1 to
129. To adjust the range of the <TT>phasor~</TT> accordingly, we multiply it by
the length of the domain (128) so that it reaches between 0 and 128, and then
@ -133,7 +133,7 @@ between the <TT>phasor~</TT> and the <TT>tabread4~</TT>.
<P>
With only these four boxes we would have essentially reinvented the
<TT>tabosc4~</TT> class. In this example, however, the multiplication
is not by a constant 128 but by a variable amount controlled by the ``squeeze"
is not by a constant 128 but by a variable amount controlled by the "squeeze"
parameter. The function of the four boxes at the right hand side of the patch
is to supply the <TT>*~</TT> object with values to scale the
<TT>phasor~</TT> by. This makes use of one more new object class:
@ -150,18 +150,18 @@ is to supply the <TT>*~</TT> object with values to scale the
number of arguments, their types (usually numbers) and their initial values.
The inlets (there will be as many as you specified creation arguments) update
the values of the message arguments, and, if the leftmost inlet is changed
(or just triggered with a ``bang" message), the message is output.
(or just triggered with a "bang" message), the message is output.
<ANAME="pdpack"></A>
<P>
In this patch the arguments are initially 0 and 50, but the number box will
update the value of the first argument, so that, as pictured, the most recent
message to leave the <TT>pack</TT> object was ``206 50". The effect of this
message to leave the <TT>pack</TT> object was "206 50". The effect of this
on the <TT>line~</TT> object below is to ramp to 206 in 50 milliseconds; in
general the output of the <TT>line~</TT> object is an audio signal that smoothly
follows the sporadically changing values of the number box labeled ``squeeze".
follows the sporadically changing values of the number box labeled "squeeze".
<P>
Finally, 128 is added to the ``squeeze" value; if ``squeeze" takes non-negative
Finally, 128 is added to the "squeeze" value; if "squeeze" takes non-negative
values (as the number box in this patch enforces), the range-setting multiplier
ranges the phasor by 128 or more. If the value is greater than 128, the effect
is that the rescaled phasor spends some fraction of its cycle stuck at the end
The amplitude of the output of <TT>tabread4~</TT> is controlled by a
second <TT>vline~</TT> object, in order to prevent discontinuities
in the output in case a new event is started while the previous event is still
playing. The ``cutoff" <TT>vline~</TT> object ramps the output down to zero
playing. The "cutoff" <TT>vline~</TT> object ramps the output down to zero
(whether or not it is playing) so that, once the output is zero, the index
of the wavetable may be changed discontinuously.
<P>
In order to start a new ``note", first, the ``cutoff" <TT>vline~</TT> object is
In order to start a new "note", first, the "cutoff" <TT>vline~</TT> object is
ramped to zero; then, after a delay of 5 msec (at which point <TT>vline~</TT> has reached zero) the phase is reset. This is done with two messages: first,
the phase is set to 1 (with no time value so that it jumps to 1 with no
ramping). The value ``1" specifies the first readable point of the wavetable,
ramping). The value "1" specifies the first readable point of the wavetable,
since we are using 4-point interpolation. Second, in the same message box,
the phase is ramped to 441,000,000 over a time period of 10,000,000 msec. (In
Pd, large numbers are shown using exponential notation; these two appear as
4.41e+08 and 1e+07.) The quotient is 44.1 (in units per millisecond) giving
a transposition of one. The upper <TT>vline~</TT> object (which generates the
phase) receives these messages via the ``r phase" object above it.
phase) receives these messages via the "r phase" object above it.
<P>
The example assumes that the wavetable is ramped smoothly to zero at either
Example C08.analog.sequencer.pd (Figure <AHREF="#fig03.15">3.15</A>) realizes the analog sequencer and envelope
generation described in Section <AHREF="node47.html#sect3.analog">3.7</A>. The ``sequence" table,
generation described in Section <AHREF="node47.html#sect3.analog">3.7</A>. The "sequence" table,
with nine elements, holds a sequence of frequencies. The <TT>phasor~</TT> object at top cycles through the sequence table at 0.6 Hertz. Non-interpolating
table lookup (<TT>tabread~</TT> instead of <TT>tabread4~</TT>) is
used to read the frequencies in discrete steps. (Such situations, in
Example D01.envelope.gen.pd (Figure <AHREF="#fig04.12">4.12</A>) shows how the <TT>line~</TT> object may
be used to generate an ADSR envelope to control a synthesis patch (only the
ADSR envelope is shown in the figure). The ``attack" button, when pressed, has
ADSR envelope is shown in the figure). The "attack" button, when pressed, has
two effects. The first (leftmost in the figure) is to set the <TT>line~</TT> object on its attack segment, with a target of 10 (the peak amplitude) over 200
msec (the attack time). Second, the attack button sets a <TT>delay 200</TT> object, so that after the attack segment is done, the decay segment can start.
The decay segment falls to a target of 1 (the sustain level) after another 2500
@ -93,10 +93,10 @@ ADSR envelope.</CAPTION>
</DIV>
<P>
The ``release" button sends the same <TT>line~</TT> object back to zero over
The "release" button sends the same <TT>line~</TT> object back to zero over
500 more milliseconds (the release time). Also, in case the
<TT>delay 200</TT> object happens to be set at the moment the ``release" button is pressed, a
``stop" message is sent to it. This prevents the ADSR generator from
<TT>delay 200</TT> object happens to be set at the moment the "release" button is pressed, a
"stop" message is sent to it. This prevents the ADSR generator from
launching its decay segment after launching its release segment.
<P>
@ -148,9 +148,9 @@ Inside the <TT>adsr</TT> abstraction.</CAPTION>
</DIV>
<P>
The attack segment goes to a target specified as ``$1" (the first
creation argument of the abstraction) over ``$2" milliseconds; these
values may be overwritten by sending numbers to the ``peak level" and ``attack"
The attack segment goes to a target specified as "$1" (the first
creation argument of the abstraction) over "$2" milliseconds; these
values may be overwritten by sending numbers to the "peak level" and "attack"
inlets. The release segment is similar, but simpler, since the target is
always zero. The hard part is the decay segment, which again must be set
off after a delay equal to the attack time (the <TT>del $2</TT> object).
@ -122,7 +122,7 @@ This has the advantage of being more explicit than the <TT>throw~</TT> /
problem.
<P>
The main job of the patch, though, is to distribute the ``note" messages to
The main job of the patch, though, is to distribute the "note" messages to
the <TT>sampvoice</TT> objects. To do this we must introduce some new Pd
objects:
@ -149,8 +149,8 @@ There is also an integer division object named <TT>div</TT> ; dividing 17 by
<ANAME="4912"></A>Polyphonic voice allocator. Creation arguments give the number of
voices in the bank and a flag (1 if voice stealing is needed, 0 if not).
The inlets are a numeric tag at left and a flag at right indicating whether
to start or stop a voice with the given tag (nonzero numbers meaning ``start"
and zero, ``stop"). The outputs are, at left, the voice number, the tag
to start or stop a voice with the given tag (nonzero numbers meaning "start"
and zero, "stop"). The outputs are, at left, the voice number, the tag
again at center, and the start/stop flag at right. In MIDI applications, the
tag can be pitch and the start/stop flag can be the note's velocity.
@ -163,13 +163,13 @@ tag can be pitch and the start/stop flag can be the note's velocity.
SRC="img398.png"
ALT="\fbox{ \texttt{makenote}}">:
<ANAME="4913"></A>Supply delayed note-off messages to match note-on messages. The inlets are
a tag and start/stop flag (``pitch" and ``velocity" in MIDI usage) and the
a tag and start/stop flag ("pitch" and "velocity" in MIDI usage) and the
desired duration in milliseconds. The tag/flag pair are repeated to
the two outlets as they are received; then, after the delay, the tag is
repeated with flag zero to stop the note after the desired duration.
<P>
The ``note" messages contain fields for pitch, amplitude, duration,
The "note" messages contain fields for pitch, amplitude, duration,
sample number, start location in the sample, rise time, and decay time. For
instance, the message,
<PRE>
@ -177,7 +177,7 @@ instance, the message,
</PRE>
(if received by the <TT>r note</TT> object)
means to play a note at pitch 60 (MIDI units), amplitude 90 dB, one second
long, from the wavetable named ``sample2", starting at a point 500 msec
long, from the wavetable named "sample2", starting at a point 500 msec
into the wavetable, with rise and decay times of 10 and 20 msec.
<P>
@ -192,7 +192,7 @@ a unique number corresponding to the note.
The next step is to use the <TT>poly</TT> object to determine which voice to play
which note. The <TT>poly</TT> object expects separate messages to start
and stop tasks (i.e., notes). So the tag and duration are first fed to the
<TT>makenote</TT> object, whose outputs include a flag (``velocity") at
<TT>makenote</TT> object, whose outputs include a flag ("velocity") at
right and the tag again at left. For each tag <TT>makenote</TT> receives, two pairs
of numbers are output, one to start the note, and another, after a delay
equal to the note duration, to stop it.
@ -200,7 +200,7 @@ equal to the note duration, to stop it.
<P>
Having treated <TT>poly</TT> to this separated input, we now have to strip
the messages corresponding to the ends of notes, since we really only need
combined ``note" messages with
combined "note" messages with
duration fields. The <TT>stripnote</TT> object does this job. Finally, the
voice number we have calculated is prepended to the seven parameters we
started with (the <TT>pack</TT> object), so that the output of the
@ -208,11 +208,11 @@ started with (the <TT>pack</TT> object), so that the output of the
<PRE>
4 60 90 1000 2 500 10 20
</PRE>
where the ``4" is the voice number output by the <TT>poly</TT> object.
where the "4" is the voice number output by the <TT>poly</TT> object.
The voice number is used to route the message
to the desired voice using the <TT>route</TT> object. The appropriate
<TT>sampvoice</TT> object then gets the original list starting with
``60".
"60".
<P>
Inside the <TT>sampvoice</TT> object (Figure <AHREF="#fig04.21">4.21</A>), the message
@ -239,20 +239,20 @@ list generated by the <TT>pack</TT> object at the center of the voice patch.
<P>
We arbitrarily decide that the ramp will last ten thousand seconds (this is the
``1e+07" appearing in the message box sent to the wavetable index generator),
"1e+07" appearing in the message box sent to the wavetable index generator),
hoping that this is at least as long as any note we will play. The ending index
is the starting index plus the number of samples to ramp through. At a
transposition factor of one, we should move by 441,000,000 samples during those
10,000,000 milliseconds, or proportionally more or less depending on the
transposition factor. This transposition factor is computed by the <TT>mtof</TT> object, dividing by 261.62 (the frequency corresponding to MIDI note 60) so
that a specified ``pitch" of 60 results in a transposition factor of one.
that a specified "pitch" of 60 results in a transposition factor of one.
<P>
These and other parameters are combined in one message
via the <TT>pack</TT> object so that the following message boxes can
generate the needed control messages. The only novelty is
the <TT>makefilename</TT> object, which converts numbers such as ``2" to
symbols such as ``sample2" so that the <TT>tabread4~</TT> object's
the <TT>makefilename</TT> object, which converts numbers such as "2" to
symbols such as "sample2" so that the <TT>tabread4~</TT> object's