This is Info file pm.info, produced by Makeinfo version 1.68 from the
input file bigpm.texi.


File: pm.info,  Node: PDF/Labels,  Next: PDF/Pages,  Prev: PDF/Create,  Up: Module List

Routines to produce formatted pages of mailing labels in PDF
************************************************************

NAME
====

   PDF::Labels - Routines to produce formatted pages of mailing labels in
PDF

SYNOPSIS
========

     use PDF::Labels;

     Requires: PDF::Create

DESCRIPTION
===========

GENERAL
-------

   Provides package PDF::Labels

   Package Global Variables:

     @PDF::Labels:PageFormats is a list of known page formats.  Each
     page format is a : delimited list of fields which provide the
     following properties about a page of labels:

     pagewidth	Width of actual page in inches
     pageheight	Height of actual page in inches
     pagexoffset	Offset from left edge of page to left
     		edge of first column of labels in inches
     pageyoffset	Offset from bottom edge of page to
     		bottom edge of lowest row of labels
     xlabels		Number of labels in each row
     ylabels		Number of labels in each column
     labelwidth	Width of each label in inches, including
     		margin
     labelheight	Height of each label in inches, including
     		margin
     labelxmar	Minimum Distance to offset printing from
     		left and right edges of label
     labelymar	Minimum distance to offset printing from
     		top and bottom edges of label
     fontsize	Size of font to use with this label
     linespacing	Line spacing (points) to use with this
     		label

SYNTAX
------

     Example

     use PDF::Create;
     use PDF::Labels;

     $pdf = new PDF::Labels(
     		$PDF::Labels::PageFormats[0],
     			filename=>'labels.pdf',
     			Author=>'PDF Labelmaker',
     			Title=>'My Labels'
     	);

     $pdf->setlabel(5);	# Start with label 5 on first page

     $pdf->label('John Doe', '1234 Some Street',
     		'Anytown, ID', '12345');
     $pdf->label('Jane Doe', '5493 Other Drive',
     		'Nowhere, CA', '92213');
     $pdf->label('Bob Smith', '392 Cedar Lane',
     		'Deep Shit, AR', '72134');

     $pdf->close();

     The above example will produce 3 labels on an 8.5x11 sheet with
     three labels in a row and 10 rows of labels.  The labels are
     2.625"x1".  This is a common sheet-feed label.  In this case, the
     three labels will be the last label of the second row and the
     first two labels of the third row.  The labels can be moved by
     changing the parameter to the setlabel call.

     Creation

     $pdf = new PDF::Labels(
     		$PageFormat,
     		PDF::Create parameters
     	)

     $PageFormat is a string containing a single element of PageFormats
     or a custom page format specification in the same format.

     PDF::Create parameters are described in the PDF::Create pod.

     Setup

     $pdf->setlabel(n)

     n is a number from 0 to maxlabels.  Subsequent calls to create
     labels will create labels starting from this position on the
     page.  Position 0 is the upper left label, working across each
     row down in columns.

     i.e.	0 1 2
     	3 4 5
     	6 7 8
     	...

     Setlabel will not go backwards.  If n is less than the current
     cursor position, a new page will be created.

     Label Creation

     $pdf->label('string1', 'string2', 'string3'[, 'string4'...])

     As much of each string as possible will be placed on a seperate
     line of the label.  If there are more strings than the label can
     hold, extra strings will not be printed.

     @(#) Labels.pm Last updated 01/02/10 18:59:54 (SCCS Version 1.8)

AUTHOR
======

   Owen DeLong, owen@delong.com


File: pm.info,  Node: PDF/Pages,  Next: PDF/Parse,  Prev: PDF/Labels,  Up: Module List

Library for parsing the PDF tree structure in Perl
**************************************************

NAME
====

   PDF::Pages - Library for parsing the PDF tree structure in Perl

SYNOPSIS
========

     use PDF ;
     use PDF::Pages ;

     $pdf_pages=PDF::Pages->new;
     $pdf_pages->ReadPageTree($pdf_struct);;

DESCRIPTION
===========

   This is a part of the more general PDF library. In this section you
will find the functions related to the page tree of a PDF file.

Constructor
===========

* new *
          This is the constructor of a new PDF tree object. It returns an
          empty PDF Page tree descriptor ( can be filled with <B ReadPageTree> ).

Methods
=======

   The available methods are :

*ReadPageTree ( pdf_struct ) *
     This method reads the information contained in the root of the page
     tree of the argument PDF document.

Copyright
=========

     Copyright 1998, Antonio Rosella antro@technologist.com

   This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

Availability
============

   The latest version of this library is available from:

   http://www.geocities.com/CapeCanaveral/Hangar/4794/

   and from CPAN .


File: pm.info,  Node: PDF/Parse,  Next: PDL,  Prev: PDF/Pages,  Up: Module List

Library with parsing functions for PDF library
**********************************************

NAME
====

   PDF::Parse - Library with parsing functions for PDF library

SYNOPSIS
========

     use PDF::Parse;

     $pdf->TargetFile($filename);
     $pdf->LoadPageInfo;

     $version = $pdf->Version;
     $bool = $pdf->IsaPDF;
     $bool = $pdf->IscryptPDF;

     $info = $pdf->GetInfo ($key);
     $pagenum = $pdf->Pages;

     @size = $pdf->PageSize ($page);
     # or
     @size = $pdf->PageSize;

     $rotation = $pdf->PageRotation ($page);
     # or
     $rotation = $pdf->PageRotation;

DESCRIPTION
===========

   The main purpose of the PDF::Parse library is to provide parsing
functions for the more general PDF library.

Methods
=======

   The available methods are:

TargetFile ( filename )
-----------------------

   This method links the filename to the pdf descriptor and parses all
kind of header information.

LoadPageInfo
------------

   This function loads the information for all pages. This process can
take some time for big PDF-files.

Version
-------

   Returns the PDF version used for writing the object file.

IsaPDF
------

   Returns true, if the file could be parsed and is a PDF-file.

IscryptPDF
----------

   Returns true if the PDF contains a crypt object. This indicates that
the data of the PDF-File is encrypted. In this case, not all function work
as expected.

GetInfo ( key )
---------------

   Returns the various information contained in the info section of a PDF
file (if present). A PDF file can have:

     a title ==> GetInfo ("Title")
     a subject ==> GetInfo ("Subject")
     an author ==> GetInfo("Author")
     a creation date ==> GetInfo("CreationDate")
     a creator ==> GetInfo("Creator")
     a producer ==> GetInfo("Producer")
     a modification date ==> GetInfo("ModDate")
     some keywords ==> GetInfo("Keywords")

Pages
-----

   Returns the number of pages of the PDF-file.

PageSize ( [ page ] )
---------------------

   Returns the size of a page in the PDF-file. If no parameter is given,
the default size of the root page will be returned. This value may be
overridden for any page.

   If the size of an individual page is requested and the page data is not
already loaded, the method LoadPageInfo will be executed. This may take
some time for large PDF-files. The size of the root page is always
available and will never execute LoadPageInfo.

PageRotation ( [ page ] )
-------------------------

   Returns the rotation of a page in the PDF-file. If no parameter is
given, the default rotation of the root page will be returned. This value
may be overridden for any page.

   If the rotation of an individual page is requested and the page data is
not already loaded, the method LoadPageInfo will be executed. This may
take some time for large PDF-files. The rotation of the root page is
always available and will never execute LoadPageInfo.

Variables
=========

   The only available variable is :

$PDF::Parse::VERSION
     Contains the version of the library installed

Copyright
=========

     Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com

   This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

Availability
============

   The latest version of this library is likely to be available from:

   http://www.geocities.com/CapeCanaveral/Hangar/4794/


File: pm.info,  Node: PDL,  Next: PDL/Audio,  Prev: PDF/Parse,  Up: Module List

Main loader of PDL default modules
**********************************

NAME
====

   PDL - Main loader of PDL default modules

DESCRIPTION
===========

   Loads the default set of modules associated with PDL, making the
functions available in the current namespace. See also
`PDL::Lite|PDL::Lite' in this node or `PDL::LiteF|PDL::LiteF' in this node
if start-up time becomes an issue.

SYNOPSIS
========

     use PDL; # Is equivalent to the following:

     use PDL::Core;
     use PDL::Ops;
     use PDL::Primitive;
     use PDL::Ufunc;
     use PDL::Basic;
     use PDL::Slices;
     use PDL::Bad;
     use PDL::Version;
     use PDL::IO::Misc;


File: pm.info,  Node: PDL/Audio,  Next: PDL/Audio/Pitches,  Prev: PDL,  Up: Module List

Some PDL functions intended for audio processing.
*************************************************

NAME
====

   PDL::Audio - Some PDL functions intended for audio processing.

SYNOPSIS
========

     use PDL::Audio;

DESCRIPTION
===========

   Oh well ;) Not much written yet! See my other modules for even worse
documentation ;)

NOTATION
--------

   Brackets around parameters indicate that the respective parameter is
optional and will be replaced with some default value when absent (or
undef, which might be different in other packages).

   The sampling frequency and duration are by default (see individual
descriptions) given in cycles/sample (or samples in case of a duration).
That means if you want to specify a duration of two seconds, you have to
multiply by the sampling frequency in HZ, and if you want to specify a
frequency of 440 Hz, you have to divide by the sampling frequency:

     # Syntax: gen_oscil duration*, frequency/
     $signal = gen_oscil 2*HZ, 440/HZ;
     # with a sampling frequency of 44100 Hertz:
     $signal = gen_oscil 2*44100, 440/44100;

   To help you, the required unit is given as a type suffix in the
parameter name. A "/" means that you have to divide by the sampling
frequency (to convert from Hertz) and a suffix of "*" indicates that a
multiplication is required.

   Most parameters named "size", "duration" (or marked with "*") can be
replaced by a piddle, which is then used to give length and from
(mono/stereo).

HEADER ATTRIBUTES
-----------------

   The following header attributes are stored and evaluated by most
functions. PDL::Audio provides mutator methods for all them (e.g.

   print "samplerate is ", $pdl->rate;  $pdl->comment("set the comment to
this string");

rate
     The sampling rate in hz.

filetype
     The filetype (wav, au etc..). Must be one of:

          FILE_NEXT FILE_AIFC FILE_RIFF FILE_BICSF FILE_NIST FILE_INRS FILE_ESPS
          FILE_SVX FILE_VOC FILE_SNDT FILE_RAW FILE_SMP FILE_SD2 FILE_AVR
          FILE_IRCAM FILE_SD1 FILE_SPPACK FILE_MUS10 FILE_HCOM FILE_PSION
          FILE_MAUD FILE_IEEE FILE_DESKMATE FILE_DESKMATE_2500 FILE_MATLAB
          FILE_ADC FILE_SOUNDEDIT FILE_SOUNDEDIT_16 FILE_DVSM FILE_MIDI
          FILE_ESIGNAL FILE_SOUNDFONT FILE_GRAVIS FILE_COMDISCO FILE_GOLDWAVE
          FILE_SRFS FILE_MIDI_SAMPLE_DUMP FILE_DIAMONDWARE FILE_REALAUDIO
          FILE_ADF FILE_SBSTUDIOII FILE_DELUSION FILE_FARANDOLE FILE_SAMPLE_DUMP
          FILE_ULTRATRACKER FILE_YAMAHA_SY85 FILE_YAMAHA_TX16 FILE_DIGIPLAYER
          FILE_COVOX FILE_SPL FILE_AVI FILE_OMF FILE_QUICKTIME FILE_ASF
          FILE_YAMAHA_SY99 FILE_KURZWEIL_2000 FILE_AIFF FILE_AU

path
     The filename (or file specification) used to load or save a file.

format
     Specifies the type the underlying file format uses. The samples will
     always be in short or long signed format.

     Must be one of

          FORMAT_NO_SND FORMAT_16_LINEAR FORMAT_8_MULAW FORMAT_8_LINEAR
          FORMAT_32_FLOAT FORMAT_32_LINEAR FORMAT_8_ALAW FORMAT_8_UNSIGNED
          FORMAT_24_LINEAR FORMAT_64_DOUBLE FORMAT_16_LINEAR_LITTLE_ENDIAN
          FORMAT_32_LINEAR_LITTLE_ENDIAN FORMAT_32_FLOAT_LITTLE_ENDIAN
          FORMAT_64_DOUBLE_LITTLE_ENDIAN FORMAT_16_UNSIGNED
          FORMAT_16_UNSIGNED_LITTLE_ENDIAN FORMAT_24_LINEAR_LITTLE_ENDIAN
          FORMAT_32_VAX_FLOAT FORMAT_12_LINEAR FORMAT_12_LINEAR_LITTLE_ENDIAN
          FORMAT_12_UNSIGNED FORMAT_12_UNSIGNED_LITTLE_ENDIAN COMPATIBLE_FORMAT

     PDL::Audio conviniently defines the following aliases for the
     following constants, that are already correct for the host byteorder:

          FORMAT_ULAW_BYTE FORMAT_ALAW_BYTE FORMAT_LINEAR_BYTE
          FORMAT_LINEAR_SHORT FORMAT_LINEAR_USHORT FORMAT_LINEAR_LONG
          FORMAT_LINEAR_FLOAT FORMAT_LINEAR_DOUBLE

comment
     The file comment (if any).

device
     The device to output audio. One of:

          DEV_DEFAULT DEV_READ_WRITE DEV_ADAT_IN DEV_AES_IN DEV_LINE_OUT
          DEV_LINE_IN DEV_MICROPHONE DEV_SPEAKERS DEV_DIGITAL_IN DEV_DIGITAL_OUT
          DEV_DAC_OUT DEV_ADAT_OUT DEV_AES_OUT DEV_DAC_FILTER DEV_MIXER
          DEV_LINE1 DEV_LINE2 DEV_LINE3 DEV_AUX_INPUT DEV_CD_IN DEV_AUX_OUTPUT
          DEV_SPDIF_IN DEV_SPDIF_OUT
          
          =back

EXPORTED CONSTANTS
------------------

   In addition to the exported constants described above (and later in the
function descriptions), this module also exports the mathematical
constants M_PI and M_2PI, so watch out for clashes!

FUNCTIONS
=========

sound_format_name format_code
-----------------------------

   Return the human-readable name of the file format with code
`format_code'.

sound_type_name type_code
-------------------------

   Return the human-readable name of the sample type with code `type_code'.

describe_audio piddle
---------------------

   Describe the audio stream contained in piddle and return it as a
string. A fresh piddle might return:

     mono sound with 27411 samples

   Whereas a freshly loaded soundfile might yield:

     stereo sound with 27411 samples, original name "kongas.wav", type 2 (RIFF),
     rate 11025/s (duration 2.49s), format 7 (8-bit unsigned)

raudio path, [option-hash], option => value, ...
------------------------------------------------

   Reads audio data into the piddle. Options can be anything, most useful
values are filetype, rate, channels and format.

     # read any file
     $pdl = raudio "file.wav";
     # read a file. if it is a raw file preset values
     $pdl = raudio "file.raw", filetype => FILE_RAW, rate => 44100, channels => 2;

waudio pdl, [option-hash], option => value, ...
-----------------------------------------------

   Writes a pdl as a file. The path is taken from the header (or the
options), e.g.:

     # write a file, using the header of another piddle
     $pdl->waudio($orig_file->gethdr);
     # write pdl as au file, take rate from the header
     $pdl->waudio(path => "piddle.au", filetype => FILE_AU, format => FORMAT_16_LINEAR;

cut_leading_silence pdl, level
------------------------------

   Cuts the leading silence (i.e. all samples with absolute value < level)
and returns the resulting part.

cut_trailing_silence pdl, level
-------------------------------

   Cuts the trailing silence.

cut_silence pdl, level
----------------------

   Calls `cut_leading_silence' and `cut_trailing_silence' and returns the
result.

playaudio pdl, [option-hash], option => value ...
-------------------------------------------------

   Play the piddle as an audio file. Options can be supplied either
through the option hash (a hash-reference), through the pdl header or the
options:

     # play a piddle that has a valid header (e.g. from raudio)
     $pdl->playaudio;
     # play it with a different samplerate
     $pdl->playaudio(rate => 22050);

ulaw2linear
-----------

linear2ulaw
-----------

alaw2linear
-----------

linear2alaw
-----------

gen_oscil duration*, freq/, phase-mod, [fm-mod/]
------------------------------------------------

gen_sawtooth duration*, freq/, phase-mod, [fm-mod/]
---------------------------------------------------

gen_square duration*, freq/, phase-mod, [fm-mod/]
-------------------------------------------------

gen_triangle duration*, freq/, phase-mod, [fm-mod/]
---------------------------------------------------

gen_pulse_train duration*, freq/, phase-mod, [fm-mod/]
------------------------------------------------------

gen_rand duration*, freq/
-------------------------

gen_rand_1f duration*
---------------------

   All of these functions generate appropriate waveforms with frequency
`freq' (cycles/sample) and phase `phase' (0..1).

   The `duration' might be either a piddle (which gives the form of the
output) or the number of samples to generate.

   The output samples are between -1 and +1 (i.e. "-1 <= s <= +1").

gen_env duration*, xvals, yvals, [base]
---------------------------------------

   Generates an interpolated envelope between the points given by xvals and
yvals.  When base == 1 (the default) then the values will be linearly
interpolated, otherwise they follow an exponential curve that is bend
inwards (base < 1) or outwards (base > 1).

     # generate a linear envelope with attack in the first 10%
     gen_env 5000, [0 1 2 9 10], [0 1 0.6 0.6 0];

gen_asymmetric_fm duration*, freq/, phase, [r , [ratio]]
--------------------------------------------------------

   `gen_asymmetric_fm' provides a way around the symmetric spectra normally
produced by FM. See Palamin and Palamin, "A Method of Generating and
Controlling Asymmetrical Spectra" JAES vol 36, no 9, Sept 88, p671-685.

gen_sum_of_cosines duration*, freq/, phase, ncosines, [fm_mod/]
---------------------------------------------------------------

   Generates a sum of n cosines `(1 + 2(cos(x) + cos(2x) + ... cos(nx)) =
sin((n+.5)x) / sin(x/2))'. Other arguments are similar to to `gen_oscil'.

gen_sine_summation duration*, freq/, phase, [nsines, [a, [b_ratio, [fm_mod/]]]]
-------------------------------------------------------------------------------

   `gen_sine_summation' provides a kind of additive synthesis. See
J.A.Moorer, "Signal Processing Aspects of Computer Music" and "The
Synthesis of Complex Audio Spectra by means of Discrete Summation
Formulae" (Stan-M-5). The basic idea is very similar to that used in
gen_sum_of_cosines generator.

   The default value for `nsines' is 1 (but zero is a valid value), for a
is 0.5 and for `b_ratio' is 1.

   (btw, either my formula is broken or the output indeed does not lie
between -1 and +1, but rather -5 .. +5).

gen_from_table duration*, frequency/, table, [phase], [fm_mod/]
---------------------------------------------------------------

   `gen_from_table' generates a waveform by repeating a waveform given in
table, linearly interpolating between successive points of the `waveform'.

partials2waveshape size*, partials, amplitudes, [phase], [fm_mod/]
------------------------------------------------------------------

   Take a list (perl list or pdl) of (integer) `partials' and a list of
`amplitudes' and generate a single wave shape that results by adding these
partial sines.

   This could (and should) be used by the `gen_from_table' generator.

gen_from_partials duration*, frequency/, partials, amplitudes, [phase], [fm_mod/]
---------------------------------------------------------------------------------

   Take a list (perl list or pdl) of (possibly noninteger) `partials' and a
list of `amplitudes' and generate the waveform resulting by summing up all
these partial sines.

filter_one_zero
---------------

filter_one_pole
---------------

filter_two_zero
---------------

filter_two_pole
---------------

filter_formant
--------------

filter_ppolar pdl, radius/, frequency/
--------------------------------------

   apply a two pole filter (given in polar form). The filter has two poles,
one at (radius,frequency), the other at (radius,-frequency). Radius is
between 0 and 1 (but less than 1), and frequency is between 0 and 0.5.
This is the standard resonator form with poles specified by the polar
coordinates of one pole.

filter_zpolar pdl, radius/, frequency/
--------------------------------------

   apply a two zero filter (given in polar form). See `filter_ppolar'.

partials2polynomial partials, [kind]
------------------------------------

   `partials2polynomial' takes a list of harmonic amplitudes and returns a
list of Chebychev polynomial coefficients. The argument `kind' determines
which kind of Chebychev polynomial we are interested in, 1st kind or 2nd
kind. (default is 1).

ring_modulate in1, in2
----------------------

   ring modulates in1 with in2 (this is just a multiply).

amplitude_modulate am_carrier, in1, in2
---------------------------------------

   amplitude modulates am_carrier and in2 with in1 (this calculates in1 *
(am_carrier + in2)).

filter_sir
----------

   Generic (short delay) impulse response filter. x is the input signal
(which is supposed to be zero for negative indices). a contains the input
(x) coefficients (a0, a1, .. an), whereas b contains the output (y)
coefficients (b0, b1, ... bn), i.e.:

     y(n) = a0 x(n) - b1 y(n-1) + a1 x(n-1) - b2 y(n-2) + a2 x(n-2) - b3 ...

   This can be used to generate fir and iir filters of any length, or even
more complicated constructs.

   `b0' (then first element of b) is being ignored currently AND SHOULD BE
SPECIFIED AS ONE FOR FUTURE COMPATIBILITY

filter_lir
----------

   Generic (long delay) impulse response filter. The difference to
filter_sir is that the filter coefficients need not be consecutive, but
instead their indices are given by the `a_x' and `b_x' (integer) vectors,
while the corresponding coefficients are in `a_y' and `b_y'. (All `a_x'
must be >= 0, while all the `b_x' must be >= 1, as you should expect).

   See filter_sir for more info.

filter_fir input, xcoeffs
-------------------------

   Apply a fir (finite impulse response) filter to input. This is the same
as calling:

     filter_sir input, xcoeffs, pdl()

filter_iir input, ycoeffs
-------------------------

   Apply a iir (infinite impulse response) filter to input. This is just
another way of saying:

     filter_sir input, pdl(1), ycoeffs

   That is, the first member of `ycoeffs' is being ignored AND SHOULD BE
SPECIFIED AS ONE FOR FUTURE COMPATIBILITY!

filter_comb input, delay*, scaler
---------------------------------

   Apply a comb filter to the piddle input. This is implemented using a
delay line with length delay (which must be 1 or larger and can be
non-integer) and a feedback scaler.

     y(n) = x(n-size-1) + scaler * y(n-size)

   See also `filter_notch'.

filter_notch input, delay*, scaler
----------------------------------

   Apply a comb filter to the piddle input. This is implemented using a
delay line with length delay (which must be 1 or larger and can be
non-integer) and a feedforward scaler.

     y(n) = x(n-size-1) * scaler + y(n-size)

   As a rule of thumb, the decay time of the feedback part is
`7*delay/(1-scaler)' samples, so to get a decay of Dur seconds, `scaler <=
1-7*delay/(Dur*Srate)'. The peak gain is `1/(1-(abs scaler))'. The peaks
(or valleys in notch's case) are evenly spaced at `srate/delay'. The
height (or depth) thereof is determined by scaler - the closer to 1.0, the
more pronounced. See Julius Smith's "An Introduction to Digital Filter
Theory" in Strawn "Digital Audio Signal Processing", or Smith's "Music
Applications of Digital Waveguides"

filter_allpass input, delay*, scaler-feedback, scaler-feedforward
-----------------------------------------------------------------

   `filter_allpass' or "moving average comb" is just like `filter_comb'
but with an added feedforward term. If `scaler-feedback == 0', we get a
moving average comb filter. If both scaler terms == 0, we get a pure delay
line.

     y(n) = feedforward*x(n-1) + x(n-size-1) + feedback*y(n-size)

design_remez_fir filter_size, bands(2,b), desired_gain(b), type, [weight(b)]         Calculates the optimal (in the Chebyshev/minimax sense) FIR filter impulse response given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands, using the Parks-McClellan exchange algorithm.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

   The first argument (the one with the funny name) sets the filter size:
`design_remez_fir' returns as many coefficients as specified via this
parameter.

   `bands' is a vector of band edge pairs (start - end), who specify the
start and end of the bands in the filter specification.  These must be
non-overlapping and sorted in increasing order. Only values between 0 (0
Hz) and `0.5' (the Nyquist frequency) are allowed.

   `des' specifies the desired gain in these bands.

   weight can be used to give each band a different weight. If absent, a
vector of ones is used.

   type is any of the exported constants `BANDPASS', `DIFFERENTIATOR' or
`HILBERT' and can be used to select various design types (use `BANDPASS'
until this is documented ;)

filter_src input, srate, [width], [sr-mod]
------------------------------------------

   Generic sampling rate conversion, implemented by convoluting input with
a sinc function of size width (default when unspecified or zero: 5).

   `srate' determines the input rate / output rate ratio, i.e. values > 1
speed up, values < 1 slow down. Values < 0 are allowed and reverse the
signal.

   If `sr_mod' is omitted, the size of the output piddle is calculcated as
`length(input)/abs(srate)', e.g. it provides the full stretched or
shrinked input signal.

   If `sr_mod' is specified it must be as large as the desired output, i.e.
it's size determines the output size. Each value in `sr_mod' is added to
`srate' at the given point in "time", so it can be used to "modulate" the
sampling rate change.

     # create a sound effect in the style of "Forbidden Planet"
     $osc = 0.3 * gen_oscil $osc, 30 / $pdl->rate;
     $output = filter_src($input, 1, 0, $osc);

filter_contrast_enhance input, enhancement
------------------------------------------

   Contrast-enhancement phase-modulates a sound file. It's like audio MSG.
The actual algorithm is (applied to the normalised sound normalized)
`sin(input*pi/2 + (enhancement*sin(input*2*pi)))'. The result is to
brighten the sound, helping it cut through a huge mix.

filter_granulate input, expansion, [option-hash], option => value...
--------------------------------------------------------------------

   `filter_granulate' "granulates" the sound file file. It is the poor
man's way to change the speed at which things happen in a recorded sound
without changing the pitches. It works by slicing the input file into
short pieces, then overlapping these slices to lengthen (or shorten) the
result; this process is sometimes known as granular synthesis, and is
similar to the "freeze" function. The duration of each slice is length -
the longer, the more like reverb the effect. The portion of the length (on
a scale from 0 to 1.0) spent on each ramp (up or down) is `ramp'. This can
control the smoothness of the result of the overlaps. The more-or-less
average time between successive segments is `hop'.  The accuracy at which
we handle this hopping is set by the float `jitter' - if `jitter' is very
small, you may get an annoying tremolo. The overall amplitude scaler on
each segment is `scaler' - this is used to try to to avoid overflows as we
add all these zillions of segments together. `expansion' determines the
input hop in relation to the output hop; an expansion-amount of 2.0 should
more or less double the length of the original, whereas an expansion-amount
of `1.0' should return something close to the original speed.

   The defaults for the arguments/options are:

     expansion	1.0
     length(*)	0.15
     scaler		0.6
     hop(*)		0.05
     ramp		0.4
     jitter(*)	0.5
     maxsize	infinity

   The parameters/options marked with (*) actually depend on the sampling
rate, and are always multiplied by the rate attribute of the piddle
internally. If the piddle lacks that attribute, 44100 is assumed. NOTE:
This is different to most other filters, but should be ok since
`filter_granulate' only makes sense for audiofiles.

audiomix pos1, data1, pos2, data2, ...
--------------------------------------

   Generate a mix of all given piddles. The resulting piddle will contain
the sum of all data-piddles at their respective positions, so some scaling
will be necessary before or after the mixing operation (e.g. scale2short).

     # mix the sound gong1 at position 0, the sound bass5 at position 22100
     # and gong2 at position 44100. The resulting piddle will be large enough
     # to accomodate all the sounds:
     $mix = audiomix 0, $gong1, 44100, $gong2, 22100,  $gong2

filter_center piddle
--------------------

   Normalize the piddle so that it is centered around `y = 0' and has
maximal amplitude of 1.

scale2short piddle
------------------

   This method takes a sound in any format (preferably float or double) and
scales it to fit into a signed short value, suitable for playback using
`playudio' or similar functions.

gen_fft_window size*, type, [$beta]
-----------------------------------

   Creates and returns a specific fft window. The type is any of the
following.  These are (case-insensitive) strings, so you might need to
quote them.

     RECTANGULAR	just ones (the identity window)
     HANNING        0.50 - 0.50 * cos (0 .. 2pi)
     HAMMING	0.54 - 0.46 * cos (0 .. 2pi)
     WELCH		1 - (-1 .. 1) ** 2
     PARZEN		the triangle window
     BARTLETT	the symmetric triangle window
     BLACKMAN2	blackman-harris window of order 2
     BLACKMAN3	blackman-harris window of order 3
     BLACKMAN4	blackman-harris window of order 4
     EXPONENTIAL	the exponential window
     KAISER		the kaiser/bessel window (using the parameter C<beta>)
     CAUCHY		the cauchy window (using the parameter <beta>)
     POISSON	the poisson window (exponential using parameter C<beta>)
     RIEMANN	the riemann window (sinc)
     GAUSSIAN	the gaussian window of order C<beta>)
     TUKEY		the tukey window (C<beta> specifies how much of the window
     		consists of ones).
     COSCOS		the cosine-squared window (a partition of unity)
     SINC 		same as RIEMANN
     HANN		same as HANNING (his name was Hann, not Hannning)

     LIST		this "type" is special in that it returns a list of all types

cplx(2,n) = rfft real(n)
------------------------

   Do a (complex fft) of real (extended to complex so that the imaginary
part is zero), and return the complex fft result. This function tries to
use `PDL::FFTW|PDL::FFTW' in this node (which is faster for large vectors)
when available, and falls back to `PDL::FFT|PDL::FFT' in this node, which
is likely to return different phase signs (due to different kernel
functions), so beware! In fact, since `rfft' has to shuffle the data when
using PDL::FFT, the fallback is always slower.

   When using PDL::FFTW, a wisdom file ~/.pdl_wisdom is used and updated,
if possible.

real(n) = irfft cplx(2,n)
-------------------------

   The inverse transformation (see `rfft'). `irfft rfft $pdl == $pdl'
always holds.

spectrum data, [norm], [window], [beta]
---------------------------------------

   Returns the spectrum of a given pdl. If norm is absent (or undef), it
returns the magnitude of the fft of data. When norm == 1 (or `eq 'NORM'',
in any case), it returns the magnitude, normalized to be between zero and
one. If norm == 0 (or `eq 'dB'', in any case), then it returns the
magnitude in dB.

   data is multiplied with window (if not undef) before calculating the
fft, and usually contains a window created with `gen_fft_window' (using
`beta'). If window is a string, it is handed over to `gen_fft_window'
(together with the beta parameter) to create a window of suitable size.

   This function could be slightly faster.

filter_convolve
---------------

rshift
------

   Positive values shift right, negative values shift left.

polynomial
----------

Cpolynomial
-----------

linear_interpolate
------------------

   Look up the ordinate x in the function given by `fx' and `fy' and
return a linearly interpolated value (somewhat optimized for many lookups).

   `fx' specifies the ordinates (x-coordinates) of the function and most be
sorted in increasing order. `fy' are the y-coordinates of the function in
these points.

bessi0
------

real2cplx
---------

fast_sin
--------

Cr2p
----

Cp2r
----

AUTHOR
======

   Marc Lehmann <pcg@goof.com>. The ideas were mostly taken from common
lisp music (CLM), by Bill Schottstaedt `bil@ccrma.stanford.edu'. I also
borrowed many explanations (and references) from the clm docs and some
code from clm.c. Highly inspiring!

SEE ALSO
========

   perl(1), *Note PDL: PDL,.


File: pm.info,  Node: PDL/Audio/Pitches,  Next: PDL/Audio/Scales,  Prev: PDL/Audio,  Up: Module List

All the standard musical pitch names.
*************************************

NAME
====

   PDL::Audio::Pitches - All the standard musical pitch names.

SYNOPSIS
========

     use PDL::Audio::Pitches;

     print a4;  # prints 440
     print bs3; # prints 261.63

DESCRIPTION
===========

   This module defines (and exports by default(!)) all standard pitch
names:

   `cdefgab' with trailing octave, e.g. a4, `g3', `c0', `a8', `interleaved
"f" and "s", e.g. as4', `bf3', `fs6'.

AUTHOR
======

   Marc Lehmann <pcg@goof.com>

SEE ALSO
========

   perl(1), *Note PDL: PDL,, *Note PDL/Audio: PDL/Audio,.


File: pm.info,  Node: PDL/Audio/Scales,  Next: PDL/AutoLoader,  Prev: PDL/Audio/Pitches,  Up: Module List

Over 1200 musical scales in PDL format.
***************************************

NAME
====

   PDL::Audio::Scales - Over 1200 musical scales in PDL format.

SYNOPSIS
========

     use PDL::Audio::Scales;

     @names = scale_list;

     # returns [1 1 1.5 5 7 8 8.5 1.2]
     $scale = get_scale 'arist_chromrej';

     ($scale, $desc) = get_scale 'arist_chromrej';
     # sets $desc to "Aristoxenos Rejected Chromatic, 6 + 3 + 21 parts 7"

EXAMPLE
=======

   The following script will play all the scales (unmodified, it will run
for hours) :)

     use PDL::Audio;
     use PDL::Audio::Scales;

     sub osc {
        my ($dur,$freq) = @_;
        (gen_asymmetric_fm $dur, $freq, 0.9, 0.6)*
        (gen_env $dur, [0, 1, 2, 9, 10], [0, 1, 0.6, 0.3, 0]);
     }

     for (scale_list) {
        my ($scale, $desc) = get_scale($_);
        my @mix;
        my $i;
        print "$_ [$desc] $scale\n";
        my $l = $scale->list;
        for (($scale*880)->list) {
           push @mix, ($i*0.2*44100    , osc 0.3*44100, $_/44100);
           push @mix, ($l*0.2*44100+0.1, osc 0.8*44100, $_/44100);
           $i++;
        }
        (audiomix @mix)->scale2short->playaudio;
     }

AUTHOR
======

   This file was translated from clm-2/scales.cl (common lisp music). the
original comments are:

     ;;; This file contains more than 1100 musical scales, each one
     ;;; a separate list variable, containing notes as cents or ratios.
     ;;; The first note of 1/1 or 0.0 cents is implied.  The data was
     ;;; translated from ftp://ftp.cs.ruu.nl/pub/MIDI/DOC/scales.zip
     ;;; (a collection of around 1100 files) by Bill Schottstaedt
     ;;; 24-Aug-95.
     ;;;
     ;;; These scales were brought together mostly by John Chalmers
     ;;; (non12@cyber.net) and Manuel Op de Coul (coul@ezh.nl).
     ;;;
     ;;; The reference for the Greek scales in this archive is:
     ;;; John H. Chalmers: Divisions of the Tetrachord, 1993.
     ;;; Frog Peak, Box 1052, Lebanon NH 03766, USA.
     ;;;
     ;;; If you know of scales not in this archive please send them to
     ;;; Manuel Op de Coul (coul@ezh.nl).

     ;;; since doing this translation, another 100 or so scales have been added:
     ;;;
     ;;; ----------------
     ;;; Date: Thu, 12 Oct 1995 06:58:42 -0700
     ;;; From: COUL@ezh.nl (Manuel Op de Coul)
     ;;; Subject: Updated scale archive
     ;;;
     ;;; The scale archive with the collections of John Chalmers and myself
     ;;; has been updated and contains now over 1250 scales.
     ;;; The scales.doc file contains the complete listing. It's found here:
     ;;;
     ;;; http://www.cs.ruu.nl/pub/MIDI/DOC/scales.doc (readme file, ASCII)
     ;;; http://www.cs.ruu.nl/pub/MIDI/DOC/scales.zip (ZIP file, binary)
     ;;;
     ;;; Use the "-a" option while unzipping. The size of the ZIP file is about
     ;;; 284 Kb. FTP is possible also from ftp.cs.ruu.nl.
     ;;; The file format of the scales is that of my tuning program Scala,
     ;;; which I hope will be available soon. The files are text files so also
     ;;; usable without it.
     ;;;
     ;;; Manuel Op de Coul    coul@ezh.nl
     ;;; ----------------

SEE ALSO
========

   perl(1), *Note PDL: PDL,, *Note PDL/Audio: PDL/Audio,.


File: pm.info,  Node: PDL/AutoLoader,  Next: PDL/Bad,  Prev: PDL/Audio/Scales,  Up: Module List

MatLab style AutoLoader for PDL
*******************************

NAME
====

   PDL::AutoLoader - MatLab style AutoLoader for PDL

SYNOPSIS
========

     use PDL::AutoLoader;
     $a = func1(...);   # Load file func1.pdl
     $b = func2(...);   # Load file func2.pdl

     $PDL::AutoLoader::Rescan = 1; # Enable re-scanning

DESCRIPTION
===========

   This module implements a MatLab style AutoLoader for PDL. If a unknown
function 'func()' is called then a file 'func.pdl' is searched for and if
found is read in to define 'func()' which is then executed.

   Files are seached for using the directories in seach path `@PDLLIB',
which is initialised from the shell environment variable `PDLLIB' which is
a colon seperated list of directories.

   e.g. in csh

     setenv PDLLIB "/home/kgb/pdllib:/local/pdllib"

   Note this is kept seperate from PERL5LIB just in case.

   As an added bonus, you can use a leading '+' on a directory name to
search not just that directory but the entire directory tree under it
(excluding symlinks).  The subdirs are determined by explicit search, and
searches occur at startup and again each time you change the number of
elements in @PDLLIB.

   For example,   setenv PDLLIB "+~kgb/PDL"

   will search /home/kgb/PDL and all its subdirectories for .pdl files.

AUTO-SCANNING
-------------

   The variable `$PDL::AutoLoader::Rescan' controls whether files are
automatically re-scanned for changes at the `perldl' command line.

   If `$PDL::AutoLoader::Rescan == 1' and the file is changed then the new
definition is reloaded auto-matically before executing the `perldl'
command line. Which means in practice you can edit files, save changes and
have `perldl' see the changes automatically.

   The default is '0' - i.e. to have this feature disabled.

   As this feature is only pertinent to the `perldl' shell it imposes no
overhead on PDL scripts. Yes Bob you can have your cake and eat it too!

   Note: files are only re-evaled if they are determined to have been
changed according to their date/time stamp.

   No doubt this interface could be improved upon some more. :-)

Sample file:
------------

     sub foo { # file 'foo.pdl' - define the 'foo' function
       my $x=shift;
       return sqrt($x**2 + $x**3 + 2);
     }
     1; # File returns true (i.e. loaded successfully)

AUTHOR
======

   Copyright(C) 1997 Karl Glazebrook (kgb@aaoepp.aao.gov.au).  All rights
reserved. There is no warranty. You are allowed to redistribute this
software / documentation under certain conditions. For details, see the
file COPYING in the PDL distribution. If this file is separated from the
PDL distribution, the copyright notice should be included in the file.

BUGS
====

   No doubt this interface could be improved upon some more. :-)

   Will probably be quite slow if `$PDL::AutoLoader::Rescan == 1' and
thousands of functions have been autoloaded.

   There could be a race condition in which the file changes while the
internal autoloader code is being executed but it should be harmless.

   Probably has not been tested enough!


File: pm.info,  Node: PDL/Bad,  Next: PDL/BadValues,  Prev: PDL/AutoLoader,  Up: Module List

PDL does not process bad values
*******************************

NAME
====

   PDL::Bad - PDL does not process bad values

DESCRIPTION
===========

   PDL has been compiled with WITH_BADVAL either 0 or undef, so it does
not contain any bad-value support code.

   Implementation details are given in *Note PDL/BadValues: PDL/BadValues,.

SYNOPSIS
========

     use PDL::Bad;
     print "\nBad value support in PDL is turned " .
         $PDL::Bad::Status ? "on" : "off" . ".\n";

     Bad value support in PDL is turned off.

VARIABLES
=========

   There are currently two variables that this module defines which may be
of use.

$PDL::Bad::Status
     Set to 0

$PDL::Bad::UseNaN
     Set to 0

BUGS
====

   None - it does nothing perfectly!

AUTHOR
======

   Doug Burke (burke@ifa.hawaii.edu), 2000.

   All rights reserved. There is no warranty. You are allowed to
redistribute this software / documentation under certain conditions. For
details, see the file COPYING in the PDL distribution. If this file is
separated from the PDL distribution, the copyright notice should be
included in the file.


File: pm.info,  Node: PDL/BadValues,  Next: PDL/Basic,  Prev: PDL/Bad,  Up: Module List

Discussion of bad value support in PDL
**************************************

NAME
====

   PDL::BadValues - Discussion of bad value support in PDL

DESCRIPTION
===========

What are bad values and why should I bother with them?
------------------------------------------------------

   Sometimes it's useful to be able to specify a certain value is 'bad' or
'missing'; for example CCDs used in astronomy produce 2D images which are
not perfect since certain areas contain invalid data due to imperfections
in the detector.  Whilst PDL's powerful index routines and all the
complicated business with dataflow, slices, etc etc mean that these
regions can be ignored in processing, it's awkward to do. It would be much
easier to be able to say `$c = $a + $b' and leave all the hassle to the
computer.

   If you're not interested in this, then you may (rightly) be concerned
with how this affects the speed of PDL, since the overhead of checking for
a bad value at each operation can be large.  Because of this, the code has
been written to be as fast as possible - particularly when operating on
piddles which do not contain bad values.  In fact, you should notice
essentially no speed difference when working with piddles which do not
contain bad values.

   However, if you do not want bad values, then PDL's WITH_BADVAL
configuration option comes to the rescue; if set to 0 or undef, the
bad-value support is ignored.  About the only time I think you'll need to
use this - I admit, I'm biased ;) - is if you have limited disk or memory
space, since the size of the code is increased (see below).

   You may also ask 'well, my computer supports IEEE NaN, so I already
have this'.  Well, yes and no - many routines, such as `y=sin(x)', will
propogate NaN's without the user having to code differently, but routines
such as qsort, or finding the median of an array, need to be re-coded to
handle bad values.  For floating-point datatypes, NaN and `Inf' are used
to flag bad values IF the option `BADVAL_USENAN' is set to 1 in your
config file.  Otherwise special values are used (`Default bad values|' in
this node).  I do not have any benchmarks to see which option is faster.

Code increase due to bad values
-------------------------------

   On an i386 machine running linux and perl 5.005_03, I measured the
following sizes (the Slatec code was compiled in, but none of the other
options: eg Karma, FFTW, GSL, and 3d were):

WITH_BADVAL = 0
     Size of blib directory after a successful make = *4963 kb*: blib/arch
     = 2485 kb and blib/lib = 1587 kb.

WITH_BADVAL = 1
     Size of blib directory after a successful make = *5723 kb*: blib/arch
     = 3178 kb and blib/lib = 1613 kb.

   So, the overall increase is *only* 15% - not much to pay for all the
wonders that bad values provides ;)

   The source code used for this test had the vast majority of the core
routines (eg those in Basic/) converted to use bad values, whilst very few
of the 'external' routines (ie everything else in the PDL distribution)
had been changed.

A quick overview
----------------

     perldl> p $PDL::Bad::Status
     1
     perldl> $a = sequence(4,3);
     perldl> p $a
     [
      [ 0  1  2  3]
      [ 4  5  6  7]
      [ 8  9 10 11]
     ]
     perldl> $a = $a->setbadif( $a % 3 == 2 )
     perldl> p $a
     [
      [  0   1 BAD   3]
      [  4 BAD   6   7]
      [BAD   9  10 BAD]
     ]
     perldl> $a *= 3
     perldl> p $a
     [
      [  0   3 BAD   9]
      [ 12 BAD  18  21]
      [BAD  27  30 BAD]
     ]
     perldl> p $a->sum
     120

   `demo bad' and `demo bad2' within `perldl|PDL::perldl' in this node
gives a demonstration of some of the things possible with bad values.
These are also available on PDL's web-site, at
`http://pdl.perl.org/demos/'.  See *Note PDL/Bad: PDL/Bad, for useful
routines for working with bad values and `t/bad.t' to see them in action.

   The intention is to:

   * not significantly affect PDL for users who don't need bad value
     support

   * be as fast as possible when bad value support is installed

   If you never want bad value support, then you set WITH_BADVAL to 0 in
`perldl.conf'; PDL then has no bad value support compiled in, so will be
as fast as it used to be.

   However, in most cases, the bad value support has a negligible affect
on speed, so you should set `WITH_CONFIG' to 1! One exception is if you
are low on memory, since the amount of code produced is larger (but only
by about 15% - see `Code increase due to bad values' in this node).

   To find out if PDL has been compiled with bad value support, look at
the values of either `$PDL::Config{WITH_BADVAL}' or $PDL::Bad::Status - if
true then it has been.

   To find out if a routine supports bad values, use the badinfo command in
`perldl|PDL::perldl' in this node or the -b option to `pdldoc|PDL::pdldoc'
in this node.  This facility is currently a 'proof of concept' (or, more
realistically, a quick hack) so expect it to be rough around the edges.

   Each piddle contains a flag - accessible via `$pdl->badflag' - to say
whether there's any bad data present:

   * If *false/0*, which means there's no bad data here, the code supplied
     by the Code option to `pp_def()' is executed. This means that the
     speed should be very close to that obtained with `WITH_BADVAL=0',
     since the only overhead is several accesses to a bit in the piddles
     state variable.

   * If *true/1*, then this says there *MAY* be bad data in the piddle, so
     use the code in the BadCode option (assuming that the `pp_def()' for
     this routine has been updated to have a BadCode key).  You get all
     the advantages of threading, as with the Code option, but it will run
     slower since you are going to have to handle the presence of bad
     values.

   If you create a piddle, it will have its bad-value flag set to 0. To
change this, use `$pdl->badflag($new_bad_status)', where `$new_bad_status'
can be 0 or 1.  When a routine creates a piddle, it's bad-value flag will
depend on the input piddles: unless over-ridden (see the CopyBadStatusCode
option to `pp_def'), the bad-value flag will be set true if any of the
input piddles contain bad values.  To check that a piddle really contains
bad data, use the `check_badflag' method.

   NOTE: propogation of the badflag

   If you change the badflag of a piddle, this change is propogated to all
the children of a piddle, so

     perldl> $a = zeroes(20,30);
     perldl> $b = $a->slice('0:10,0:10');
     perldl> $c = $b->slice(',(2)');
     perldl> print ">>c: ", $c->badflag, "\n";
     >>c: 0
     perldl> $a->badflag(1);
     perldl> print ">>c: ", $c->badflag, "\n";
     >>c: 1

   No change is made to the parents of a piddle, so

     perldl> print ">>a: ", $a->badflag, "\n";
     >>a: 1
     perldl> $c->badflag(0);
     perldl> print ">>a: ", $a->badflag, "\n";
     >>a: 1

   Thoughts:

   * the badflag can ONLY be cleared IF a piddle has NO parents, and that
     this change will propogate to all the children of that piddle. I am
     not so keen on this anymore (too awkward to code, for one).

   * `$a->badflag(1)' should propogate the badflag to BOTH parents and
     children.

   This shouldn't be hard to implement (although an initial attempt
failed!).  Does it make sense though? There's also the issue of what
happens if you change the badvalue of a piddle - should these propogate to
children/parents (yes) or whether you should only be able to change the
badvalue at the 'top' level - ie those piddles which do not have parents.

   The `orig_badvalue()' method returns the compile-time value for a given
datatype. It works on piddles, PDL::Type objects, and numbers - eg

     $pdl->orig_badvalue(), byte->orig_badvalue(), and orig_badvalue(4).

   It also has a horrible name...

   To get the current bad value, use the `badvalue()' method - it has the
same syntax as `orig_badvalue()'.

   To change the current bad value, supply the new number to badvalue - eg

     $pdl->badvalue(2.3), byte->badvalue(2), badvalue(5,-3e34).

   Note: the value is silently converted to the correct C type, and
returned - ie `byte->badvalue(-26)' returns 230 on my linux machine.  It
is also a nop for floating-point types when `BADVAL_USENAN' is true.

   Note that changes to the bad value are *NOT* propogated to
previously-created piddles - they will still have the bad value set, but
suddenly the elements that were bad will become 'good', but containing the
old bad value.  See discussion below.  It's not a problem for
floating-point types, since you can't change their badvalue.

Bad values and boolean operators
--------------------------------

   For those boolean operators in `PDL::Ops|PDL::Ops' in this node,
evaluation on a bad value returns the bad value.  Whilst this means that

     $mask = $img > $thresh;

   correctly propogates bad values, it *will* cause problems for checks
such as

     do_something() if any( $img > $thresh );

   which need to be re-written as something like

     do_something() if any( setbadtoval( ($img > $thresh), 0 ) );

   When using one of the 'projection' functions in `PDL::Ufunc|PDL::Ufunc'
in this node - such as `orover|PDL::Ufunc' in this node - bad values are
skipped over (see the documentation of these functions for the current
(poor) handling of the case when all elements are bad).

A bad value for each piddle, and related issues
-----------------------------------------------

   The following is relevant only for integer types, where there is a
choice of value to use as the bad flag.

   Currently, there is one bad value for each datatype. The code is
written so that we could have a separate bad value for each piddle (stored
in the pdl structure) - this would then remove the current problem of:

     perldl> $a = byte( 1, 2, byte->badvalue, 4, 5 );
     perldl> p $a;
     [1 2 255 4 5]
     perldl> $a->badflag(1)
     perldl> p $a;
     [1 2 BAD 4 5]
     perldl> byte->badvalue(0);
     perldl> p $a;
     [1 2 255 4 5]

   ie the bad value in `$a' has lost its *bad* status using the current
implementation.  It would almost certainly cause problems elsewhere though!

IMPLEMENTATION DETAILS
======================

   During a `perl Makefile.PL', the file `Basic/Core/badsupport.p' is
created; this file contains the values of the WITH_BADVAL and
`BADVAL_USENAN' variables, and should be used by code that is executed
before the `PDL::Config' file is created (e.g. `Basic/Core/pdlcore.c.PL'.
However, most PDL code will just need to access the `%PDL::Config' array
(e.g. `Basic/Bad/bad.pd') to find out whether bad-value support is
required.

   A new flag has been added to the state of a piddle - `PDL_BADVAL'. If
unset, then the piddle does not contain bad values, and so all the support
code can be ignored. If set, it does not guarantee that bad values are
present, just that they should be checked for. Thanks to Christian,
`badflag()' - which sets/clears this flag (see `Basic/Bad/bad.pd') - will
update ALL the children/grandchildren/etc of a piddle if its state changes
(see `badflag' in `Basic/Bad/bad.pd' and `propogate_badflag' in
`Basic/Core/Core.xs.PL').  It's not clear what to do with parents: I can
see the reason for propogating a 'set badflag' request to parents, but I
think a child should NOT be able to clear the badflag of a parent.
There's also the issue of what happens when you change the bad value for a
piddle.

   The `pdl_trans' structure has been extended to include an integer value,
`bvalflag', which acts as a switch to tell the code whether to handle bad
values or not. This value is set if any of the input piddles have their
`PDL_BADVAL' flag set (although this code can be replaced by setting
`FindBadStateCode' in pp_def).  The logic of the check is going to get a
tad more complicated if I allow routines to fall back to using the Code
section for floating-point types (ie those routines with `NoBadifNaN => 1'
when `BADVAL_USENAN' is true).

   The bad values for the integer types are now stored in a structure
within the Core PDL structure - `PDL.bvals' (eg
`Basic/Core/pdlcore.h.PL'); see also `typedef badvals' in
`Basic/Core/pdl.h.PL' and the BOOT code of `Basic/Core/Core.xs.PL' where
the values are initialised to (hopefully) sensible values.  See
`PDL/Bad/bad.pd' for read/write routines to the values.

   All this means that the internals of PDL are not binary compatible with
PDL 2.1.1 and earlier; external modules will need to be recompiled.

Why not make a PDL subclass?
----------------------------

   The support for bad values could have been done as a PDL sub-class.
The advantage of this approach would be that you only load in the code to
handle bad values if you actually want to use them.  The downside is that
the code then gets separated: any bug fixes/improvements have to be done
to the code in two different files.  With the present approach the code is
in the same `pp_def' function (although there is still the problem that
both Code and BadCode sections need updating).

Default bad values
------------------

   The default/original bad values are set to (taken from the Starlink
distribution):

     #include <limits.h>

     PDL_Byte    ==  UCHAR_MAX
     PDL_Short   ==   SHRT_MIN
     PDL_Ushort  ==  USHRT_MAX
     PDL_Long    ==    INT_MIN

   If `BADVAL_USENAN == 0', then we also have

     PDL_Float   ==   -FLT_MAX
     PDL_Double  ==   -DBL_MAX

   otherwise all of NaN, `+Inf', and `-Inf' are taken to be bad for
floating-point types.  In this case, the bad value can't be changed,
unlike the integer types.

How do I change a routine to handle bad values?
-----------------------------------------------

   Examples can be found in most of the `*.pd' files in `Basic/' (and
hopefully many more places soon!).  Some of the logic might appear a bit
unclear - that's probably because it is! Comments appreciated.

   All routines should automatically propogate the bad status flag to
output piddles, unless you declare otherwise.

   If a routine explicitly deals with bad values, you must provide this
option to pp_def:

     HandleBad => 1

   This ensures that the correct variables are initialised for the
`$ISBAD' etc macros. It is also used by the automatic document-creation
routines to provide default information on the bad value support of a
routine without the user having to type it themselves (this is in its
early stages).

   To flag a routine as NOT handling bad values, use

     HandleBad => 0

   This should cause the routine to print a warning if it's sent any
piddles with the bad flag set. Primitive's intover has had this set -
since it would be awkward to convert - but I've not tried it out to see if
it works.

   If you want to handle bad values but not set the state of all the output
piddles, or if it's only one input piddle that's important, then look at
the PP rules `NewXSFindBadStatus' and `NewXSCopyBadStatus' and the
corresponding `pp_def' options:

FindBadStatusCode
     By default, FindBadStatusCode creates code which sets
     `__privtrans->bvalflag' depending on the state of the bad flag of the
     input piddles: see `findbadstatus' in `Basic/Gen/PP.pm'.

CopyBadStatusCode
     The default code here is a bit simpler than for FindBadStatusCode:
     the bad flag of the output piddles are set if `__privtrans->bvalflag'
     is true after the code has been evaluated.  Sometimes
     CopyBadStatusCode is set to an empty string, with the responsibility
     of setting the badflag of the output piddle left to the BadCode
     section (e.g. the `xxxover' routines in
     `Basic/Primitive/primitive.pd').

   If you have a routine that you want to be able to use as inplace, look
at the routines in `bad.pd' (or `ops.pd') which use the Inplace option to
see how the bad flag is propogated to children using the
`xxxBadStatusCode' options.  I decided not to automate this as rules would
be a little complex, since not every inplace op will need to propogate the
badflag (eg unary functions).

   If the option

     HandleBad => 1

   is given, then many things happen.  For integer types, the readdata code
automatically creates a variable called `<pdl name>_badval', which
contains the bad value for that piddle (see `get_xsdatapdecl()' in
`Basic/Gen/PP/PdlParObjs.pm').  However, do not hard code this name into
your code!  Instead use macros (thanks to Tuomas for the suggestion):

     '$ISBAD(a(n=>1))'  expands to '$a(n=>1) == a_badval'
     '$ISGOOD(a())'                '$a()     != a_badval'
     '$SETBAD(bob())'              '$bob()    = bob_badval'

   well, the `$a(...)' is expanded as well. Also, you can use a `$' before
the pdl name, if you so wish, but it begins to look like line noise - eg
`$ISGOOD($a())'.

   If you cache a piddle value in a variable - eg index in `slices.pd' -
the following routines are useful:

     '$ISBADVAR(c_var,pdl)'       'c_var == pdl_badval'
     '$ISGOODVAR(c_var,pdl)'      'c_var != pdl_badval'
     '$SETBADVAR(c_var,pdl)'      'c_var  = pdl_badval'

   The following have been introduced, They may need playing around with to
improve their use.

     '$PPISBAD(CHILD,[i])          'CHILD_physdatap[i] == CHILD_badval'
     '$PPISGOOD(CHILD,[i])         'CHILD_physdatap[i] != CHILD_badval'
     '$PPSETBAD(CHILD,[i])         'CHILD_physdatap[i]  = CHILD_badval'

   If `BADVAL_USENAN' is set, then it's a bit different for float and
double, where we consider NaN, `+Inf', and `-Inf' all to be bad. In this
case:

     ISBAD   becomes   finite(piddle) == 0
     ISGOOD            finite(piddle) != 0
     SETBAD            piddle          = NaN

   where the value for NaN is discussed below in `Handling NaN values|' in
this node.

   This all means that you can change

     Code => '$a() = $b() + $c();'

   to

     BadCode => 'if ( $ISBAD(b()) || $ISBAD(c()) ) {
                   $SETBAD(a());
                 } else {
                   $a() = $b() + $c();
                 }'

   leaving Code as it is. PP::PDLCode will then create a loop something
like

     if ( __trans->bvalflag ) {
          threadloop over BadCode
     } else {
          threadloop over Code
     }

   (it's probably easier to just look at the `.xs' file to see what goes
on).

Going beyond the Code section
-----------------------------

   Similar to BadCode, there's `BadBackCode', and `BadRedoDimsCode'.

   Handling `EquivCPOffsCode' is a bit different: under the assumption
that the only access to data is via the `$EQUIVCPOFFS(i,j)' macro, then we
can automatically create the 'bad' version of it; see the
`[EquivCPOffsCode]' and `[Code]' rules in *Note PDL/PP: PDL/PP,.

Macro access to the bad flag of a piddle
----------------------------------------

   Macros have been provided to provide access to the bad-flag status of a
pdl:

     '$PDLSTATEISBAD(a)'    -> '($PDL(a)->state & PDL_BADVAL) > 0'
     '$PDLSTATEISGOOD(a)'      '($PDL(a)->state & PDL_BADVAL) == 0'

     '$PDLSTATESETBAD(a)'      '$PDL(a)->state |= PDL_BADVAL'
     '$PDLSTATESETGOOD(a)'     '$PDL(a)->state &= ~PDL_BADVAL'

   For use in `xxxxBadStatusCode' (+ other stuff that goes into the INIT:
section) there are:

     '$SETPDLSTATEBAD(a)'       -> 'a->state |= PDL_BADVAL'
     '$SETPDLSTATEGOOD(a)'      -> 'a->state &= ~PDL_BADVAL'

     '$ISPDLSTATEBAD(a)'        -> '((a->state & PDL_BADVAL) > 0)'
     '$ISPDLSTATEGOOD(a)'       -> '((a->state & PDL_BADVAL) == 0)'

Handling NaN values
-------------------

   There are two issues:

NaN as the bad value
     which is done.  To select, set `BADVAL_USENAN' to 1 in perldl.conf; a
     value of 0 falls back to treating the floating-point types the same
     as the integers.  I need to do some benchmarks to see which is faster,
     and whether it's dependent on machines (Linux seems to slow down much
     more than my sparc machine in some very simple tests I did).

Ignoring BadCode sections
     which is not.

   For *simple* routines processing floating-point numbers, we should let
the computer process the bad values (ie NaN and `Inf' values) instead of
using the code in the BadCode section.  Many such routines have been
labelled using `NoBadifNaN => 1'; however this is currently *ignored* by
PDL::PP.

   For these routines, we want to use the Code section if

     the piddle does not have its bad flag set
     the datatype is a float or double

   otherwise we use the BadCode section.  This is *NOT IMPLEMENTED*, as it
will require reasonable hacking of PP::PDLCode!

   There's also the problem of how we handle 'exceptions' - since `$a =
pdl(2) / pdl(0)' produces a bad value but doesn't update the badflag value
of the piddle.  Can we catch an exception, or do we have to trap for this
(e.g. search for exception in `Basic/Ops/ops.pd')?

   Checking for `Nan', and `Inf' is done by using the `finite()' system
call.  If you want to set a value to the NaN value, the following bit of
code can be used (this can be found in both `Basic/Core/Core.xs.PL' and
`Basic/Bad/bad.pd'):

     /* for big-endian machines */
     static union { unsigned char __c[4]; float __d; }
           __pdl_nan = { { 0x7f, 0xc0, 0, 0 } };

     /* for little-endian machines */
     static union { unsigned char __c[4]; float __d; }
           __pdl_nan = { { 0, 0, 0xc0, 0x7f } };

   To find out whether a particular machine is big endian, use the routine
`PDL::Core::Dev::isbigendian()'.

WHAT ABOUT DOCUMENTATION?
=========================

   One of the strengths of PDL is it's on-line documentation. The aim is
to use this system to provide informtion on how/if a routine supports bad
values: in many cases `pp_def()' contains all the information anyway, so
the function-writer doesn't need to do anything at all! For the cases when
this is not sufficient, there's the BadDoc option. For code written at the
perl level - ie in a .pm file - use the `=for bad' pod directive.

   This information will be available via man/pod2man/html documenation.
It's also accessible from the `perldl' shell - using the badinfo command -
and the `pdldoc' shell command - using the -b option.

   This support is at a very early stage - ie not much thought has gone
into it: comments are welcome; improvements to the code preferred ;) One
awkward problem is for `*.pm' code: you have to write a `*.pm.PL' file
which only inserts the `=for bad' directive (+ text) if bad value support
is compiled in. In fact, this is a pain when handling bad values at the
perl, rather than PDL::PP, level: perhaps I should just scrap the
WITH_BADVAL option...

CURRENT ISSUES
==============

   There are a number of areas that need work, user input, or both!  They
are mentioned elsewhere in this document, but this is just to make sure
they don't get lost.

Trapping invalid mathematical operations
----------------------------------------

   Should we add exceptions to the functions in `PDL::Ops' to set the
output bad for out-of-range input values?

     perldl> p log10(pdl(10,100,-1))

   I would like the above to produce "[1 2 BAD]", but this would slow down
operations on all piddles.  We could check for NaN/`Inf' values after the
operation, but I doubt that would be any faster.

Integration with NaN
--------------------

   When `BADVAL_USENAN' is true, the routines in `PDL::Ops' should just
fall through to the Code section - ie don't use BadCode - for float and
double data types.

Global versus per-piddle bad values
-----------------------------------

   I think all that's needed is to change the routines in
`Basic/Core/pdlconv.c.PL', although there's bound to be complications.  It
would also mean that the pdl structure would need to have a variable to
store its bad value, which would mean binary incompatability with previous
versions of PDL with bad value support.

Dataflow of the badflag
-----------------------

   Currently changes to the bad flag are propogated to the children of a
piddle, but perhaps they should also be passed on to the parents as well.

EVERYTHING ELSE
===============

   The build process has been affected. The following files are now
created during the build:

     Basic/Core/pdlcore.h      pdlcore.h.PL
                pdlcore.c      pdlcore.c.PL
                pdlapi.c       pdlapi.c.PL
                Core.xs        Core.xs.PL
                Core.pm        Core.pm.PL

   Several new files have been added:

     Basic/Pod/Badvalues.pod (ie this file)

     t/bad.t

     Basic/Bad/
     Basic/Bad/Makefile.PL
               bad.pd

     IO/NDF/NDF.xs.PL

   etc

TODO/SUGGESTIONS
================

   * Look at using per-piddle bad values.  Would mean a change to the pdl
     structure (ie binary incompatability) and the routines in
     `Basic/Core/pdlconv.c.PL' would need changing to handle this.  Most
     other routines *should not* need to be changed ...

   * what to do about `$b = pdl(-2); $a = log10($b)' - `$a' should be set
     bad, but it currently isn't.

   * Allow the operations in PDL::Ops to skip the check for bad values
     when using NaN as a bad value and processing a floating-point piddle.
     Needs a fair bit of work to PDL::PP::PDLCode.

   * `$pdl->baddata()' now updates all the children of this piddle as
     well. However, not sure what to do with parents, since:

          $b = $a->slice();
          $b->baddata(0)

     doesn't mean that `$a' shouldn't have it's badvalue cleared.
     however, after

          $b->baddata(1)

     it's sensible to assume that the parents now get flagged as
     containing bad values.

     PERHAPS you can only clear the bad value flag if you are NOT a child
     of another piddle, whereas if you set the flag then all children AND
     parents should be set as well?

     Similarly, if you change the bad value in a piddle, should this be
     propogated to parent & children? Or should you only be able to do
     this on the 'top-level' piddle? Nasty...

   * get some code set up to do benchmarks to see how much things are
     slowed down (and to check that I haven't messed things up if
     WITH_BADVAL is 0/undef).

   * some of the names aren't appealing - I'm thinking of `orig_badvalue()'
     in `Basic/Bad/bad.pd' in particular. Any suggestions appreciated.

AUTHOR
======

   Copyright (C) Doug Burke (burke@ifa.hawaii.edu), 2000.  Commercial
reproduction of this documentation in a different format is forbidden.


