//
//      Help text
//
//        Copyright (c) 2002-2003 Jim Peters <http://uazu.net/>.
//        Released under the GNU GPL version 2 as published by the
//        Free Software Foundation.  See the file COPYING for details,
//        or visit <http://www.gnu.org/copyleft/gpl.html>.
//

extern char *helptext_src;

//
//	Generate full helptext.  Returns: StrDup'd string
//

#include "all.h"

char *
gen_helptext() {
   char *p, *q, *r;
   char *list;

   // Generate the list of filters
   {
      StrStream *ss= strstream_open(32768);
      FILE *out= ss->out;
      fid_list_filters(out);
      list= strstream_close(ss);
      if (!list) error("Help-text has overflowed internal limit");
   }
   
   scr_zap();
   scr_wrap(78, "      ");
   p= helptext_src;
   while (*p) {
      if (p[0] == '#' && p[1] == '#' && p[2] == 'D') {
	 p += 3;
	 for (q= list; *q; ) {
	    for (r= q; *r && *r != '\n'; r++) ;
	    if (*r) *r++= 0;
	    scr_prw("%s\n", q);
	    q= r;
	 }
	 continue;
      }
      SCR_PUTC(*p++);
   }

   return scr_dup();
}

//
//	
//

static char *helptext_src= "
Welcome to Fiview, an FIR/IIR filter design, viewing and comparison tool
------------------------------------------------------------------------

This is the help-text, which can be brought up at any point by
pressing 'h' or F1.  This is being viewed in the built-in pager, which
may be controlled using the following keys:

  Up/Down arrow   Up or down a line at a time
  PageUp/PageDn   Up or down a page at a time
  BackSp/Space    Up or down a page at a time
  d               Down a half-page
  Return          Down a line

This text can also be viewed using a command line pager, for example:

  fiview -h | more


Legal stuff
-----------

  Fiview: an FIR/IIR filter design, viewing and comparison tool:
  Copyright (c) 2002-2003 Jim Peters, <http://uazu.net/>, all rights
  reserved.  Released under the GNU General Public Licence version 2.
  See the file COPYING for details, or visit <http://www.fsf.org>.

  The SDL library code is released under the GNU Lesser General Public
  Licence version 2 or later.  See file COPYING.LIB for details.  See
  <http://libsdl.org/> for more information about this project.

  Much of the filter design code was based on 'mkfilter' by Tony
  Fisher; see here: <http://www-users.cs.york.ac.uk/~fisher/>.  
  Dr Fisher died in February 2000 (see his site for a tribute), but
  confirmation that his code could be used was given by Anthony Moulds
  of the University of York.  See file 'fidlib/fidmkf.c'.

  \"This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License 
  version 2 as published by the Free Software Foundation.\"

  \"This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.\"

  \"You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  USA\"


Keyboard and mouse control
--------------------------

These keys apply at all times:

  1-9         The digits switch between the different loaded filters
  Esc or q    Quit the program
  F1          Switch to this help display
  F2          Switch to the filter information display
  F3          Switch to the frequency response display
  F4          Switch to the time response display

As you've probably noticed, the frequency and time responses are shown
constantly at the top of the screen in miniature.  The large area
where this text appears is the area in which the different displays
appear.  The filter information and help-text displays use the pager,
whose keys were listed above.

The frequency and time-response displays are controlled as follows:

  Left/Right    Move the view left or right by 25% of the display width
  PageUp/PageDn Move the view left or right by 100% of the display width
  BackSp/Space  Move the view left or right by 100% of the display width
  Up            Zoom out
  Down          Zoom in
  a             Auto-adjust to the most interesting part of the response

The shaded area in the miniature time or frequency display always
follows the movements in the main display, helping you keep track of
what you are looking at.

Note that the viewing window ranges stay the same as you switch
between different filters using the 1-9 keys.  This allows you to
compare the response in a critical area of two filters by simply
switching between them.  However, if they are different types of
filters, you'll probably want to press 'A' after switching to get the
interesting bit back into view.


The frequency display
---------------------

This shows the frequency response.  The mini display at the top shows
the range from 0.0 to 0.5 of the sampling rate.  However, the range
actually goes on beyond that (wrapping around, mirrored).  The main
display allows you to view slightly outside the 0.0 to 0.5 range to
make sense of the shape of some filter responses such as low-pass and
high-pass filters.

When the filter is first loaded it is scanned to find its major
features.  A guess is made to the type of the filter, and a certain
level is selected as representing the '100%' level for the filter.
This needn't necessarily be the peak response -- for example, for a
low-pass filter, the response at 0Hz (DC) is taken to be the 100%
level, because there may be ripples away from 0Hz.

This is the meaning of the percentage values displayed as the mouse
moves over the display.  Also displayed are the frequency of that
pixel and the actual range of response values covered by that pixel.

The blue lines going across the display are the phase values.  Note
that when the response is very low (less than 1e-10 compared to the
100% level, for example), the calculated phase can become unreliable
due to the accuracy of 64-bit floating point calculation.  This should
help explain any 'noise' areas you see in the phase display.  This
noise also shows up as unexpected min/max points in the 'm' display
(see below).

Note that the phase display depends on which point you measure from.
For example, a low pass filter will often show very steep phase
changes in the passband.  However, if you take into account the delay
of the filter, these can be made to look flat, moving the steep phase
lines into the stopband.

If you press and hold the 'm' key, a number of rulers appear on the
display.  These show all the minima and maxima as calculated for the
current display, along with any 50% crossing points.  The labels for
each line are always attached to that line somewhere, and response
labels try to get as close to their min/max as possible, but if there
is reduced space, they might be forced elsewhere on the display.  Zoom
in if it is too confusing.

It is also possible to feed test signals to the filter using this
screen, to see how it responds.  For example, type 'ts1<Return>' to
test the filter with 1Hz/sec upwards-sweeping tones, or 'tw8<Return>'
to test it with 8-period wavelets.  Type 't<Return>' to exit testing
mode.  See the \"Filter testing mode\" section below for full details
of this.

Also log-scale views are possible by pressing the 'L' key and then a
digit to indicate the number of 10dB ranges to display, or some other
key to return to the normal linear display.

Summary of special frequency-display keys:

  a     Auto-adjust to the most interesting part of the response
  m     Show rulers and min/max/50% points
  t     Set a testing mode
  x     Expand the vertical range to take in any out-of-range values
  z     Zoom the vertical range to show low-response areas
  l     Change to/from log-scale view


The time-response display
-------------------------

The time-response display shows which samples out of your data stream
will be taken into account by this particular filter.  Time zero is at
the right of the display, and earlier times come before.

This time-response is actually just the impulse response of the
filter reversed.  For an IIR filter, it is also the equivalent FIR
that could be used to emulate it.

When the filters are loaded, the number of data samples required for the
filter to calculate an accurate value are found (see the information
display for these details).  This information is also available when
moving the mouse over the display, along with the sample count, time and
response values.

It is useful to see how broad a chunk of data a particular filter works
on, as this will give you an idea of how much it will blur information
across time.  For example, filters with very sharp responses will
probably require a great deal of data, but that is not necessarily the
best option, because transient wave-streams might hardly show up with
such filters.  Comparing both frequency response and time-response
between different filters should help in judging the balance to make
between these factors for a particular application.

Summary of special time-display keys:

  a     Auto-adjust to the most interesting part of the response
  z     Zoom in vertical scale to show any low-amplitude signals


Command-line invocation
-----------------------

Type 'fiview' on its own to get a summary of current options (which
might include some not mentioned here).  Here are some example
command-lines:

  fiview -i LpBe4/0.01

This loads up a predefined filter type, a low-pass Bessel 4th order
filter, using a cut-off frequency of 0.01 times the sampling rate.

  fiview 200 -i LpBe4/2

This loads up exactly the same filter, except in this case the
sampling rate of 200Hz is specified, and the cut-off is now given in
Hz (==2Hz).  The sampling rate is also used in the app to display
values in Hz.

  fiview 200 -i LpBe2/2, LpBe4/2, LpBe6/2, LpBe8/2

This loads up a set of filters, which are mapped to the keys 1-4.
Actually, this set of filters could be more efficiently written by
specifying the frequency using -f:

  fiview 200 -f 2 -i LpBe2,LpBe4,LpBe6,LpBe8

All of the filters above default to the given -f frequency of 2Hz as
no frequency is mentioned after them.  This also works for pre-defined
filters that require frequency ranges.  For example, the following two
commands are equivalent:

  fiview 200 -i BpBe8/2-3
  fiview 200 -f 2-3 -i BpBe8

You are not just limited to a single filter stage per display.  See
below (\"Format of filter specification files\") for more information
on this, but as an example this filter combines two band-stop filters
and a low-pass filter in one display:

  fiview 200 -i LpBe4/20 x BsBu4/5-6 x BsBu4/9-10

For comparing a number of filters of different types, the -a adjust
option is useful.  This iteratively adjusts the filter 50% (~-3dB)
points to meet the frequency values you specify, instead of using the
estimates given by the filter design routines.  For example:

  fiview 200 -a -f 10 -i LpBe2,LpBe4,LpBu2,LpBu4

In all the above examples, I have been using the -i immediate option,
which allows filters to be specified on the command line.  However,
filter specifications can also be read from files, in which case the
-i is omitted and the filenames are listed instead.  For example:

  fiview 200 test_filters_1 test_filters_2

You can also specify default frequencies using -f as before, in which
case they are used by any filters within the files that don't have
frequencies specified.  For example:

  fiview 200 -f 12.5 test_filters

@@@ Add notes about -F and -W options


Output files
------------

Fiview creates two output files in the current directory whenever it
runs.  The first file \'fiview.log\' contains all the text that
appears on the filter information display for each of the filters.
This includes the example code, with the analysis in the comments.

The second file \'fiview.coef\' contains all of the filters expressed
purely in terms of their FIR and IIR coefficients, and in a format
which can be re-read into Fiview on a later run as a specification
file.  This is intended to allow external tools to use Fiview to
design a filter and then get access to the resulting coefficients for
further processing.  For this application, use the -Q option to quit
Fiview once the analysis is complete, before bringing up the user
interface.


Format of filter specification files
------------------------------------

A filter specification file may contain one or more different filters,
separated (or terminated) by ',' or ';' characters.  Comments may also
appear, using a line of their own with '#' after any initial white
space.

A specification can be given in terms of IIR/FIR coefficients and the
predefined filter types.  For example, just using coefficients:

  # Test filter
  0.9972 / -1 1.9955 -0.9971 x 1 -1.9985 1 
  / -1 1.9959 -0.9973 x 1 -1.9985 1

or using a predefined filter type:

  # Low-pass bessel, order 3
  LpBe3/0.05

or:

  # Band-pass butterworth, order 5
  BpBu5/0.05-0.08

or using combinations:

  # Some strange filter
  0.9972 / -1 1.9955 -0.9971 x 1 -1.9985 1 x LpBe3/0.05;

  # Some other strange filter
  LpBe3/0.05 x LpBe5/0.03


When a filter is given in terms of FIR/IIR coefficients, use 'x' to
start an FIR list, and '/' to start an IIR list.  The first list is
assumed to be an FIR list if no 'x' or '/' is included.  The order of
coefficients compared to time '0' is closest first to farthest last.
So 'x 0 0 1' would be a delay of two samples.

For predefined filter types, remember that the frequency or frequency
range can be omitted if it is given on the command-line.  So for
example, this file could generate a selection of Bessel low-pass
filters, assuming the -f option is given on the command-line:

  # Bessel low-pass filters of different orders
  LpBe1;
  LpBe2;
  LpBe3;
  LpBe4;

See below for the list of predefined filters.  Predefined filters can
only be combined using 'x', but beyond that there are no limits -- you
can combine as many as you wish, with any combination of other IIR/FIR
filters.


Filter types
------------

(see below for notes on these filters)

##D


Filter notes
------------

Bessel: This IIR filter gives a nice domed response in frequency, and
  also a nice domed response in time.  This is something approaching
  the ideal balance between time and frequency response for the
  display for applications like BWView (although I'm currently using a
  Blackman window there).

Butterworth: This IIR filter gives flat responses away from the
  transition areas, and sharp transitions, especially as the order
  increases.  However, this sharp frequency response is paid for with
  a wider and wider (i.e. more blurry) time-response.

Chebychev: This IIR filter exchanges some of the flatness in the
  passband of the Butterworth filter for a sharper fall-off at the
  cut-off frequency.  The resulting filter also takes more time to
  settle (see the time response).  The amount of permitted passband
  ripple is specified in dB, and should be negative, for example:
  \"LpCh4/-0.1\" or \"LpCh4/-1\".

All of these types come in a matched-Z version (LpBeZ,HpBuZ,etc) which
uses the matched-Z transform instead of the bilinear transform.  This
eliminates the FIR part of the filter for low-pass filters, making
them pure IIR.  You really need to read what Tony Fisher has to say
about this on his site to understand whether to use it or not.
Briefly he suggests this option is useful for generating Bessel
filters with optimally linear phase response, or for generating
filters that execute slightly faster, but the bilinear transform is
otherwise superior.

Resonators: These IIR filters are based on oscillators, equivalent to
  a tuned circuit.  The <value> gives the narrowness of the resonator
  response.  Low values give wider response and faster decay to the
  oscillations.  Infinity can be represented using a value of '0',
  which gives a pure oscillator -- for example: \"BpRe/0/0.1\".  The
  all-pass version (ApRe) has unit response, but the phase varies with
  frequency, changing rapidly around the resonant frequency.  These
  are all from mkfilter -- Tony Fisher there suggests that band-stop
  and band-pass filters made with resonators are often more efficient
  and better-behaved than Butterworth filters.  See the mkfilter docs
  for more info on all of this (the URL is close to the top of this
  file).

Proportional-integral: I don't know what these are for, and they're
  not documented on the mkfilter site either.  The IIR part, at least,
  just totals up all the samples received (an 'integral').  I guess
  you'll know if you want this.  This is probably the digital version
  of some analogue op-amp technique.  Also note that they don't
  display at all well in either mkfilter or fiview!

Biquad filters: These are based on Robert Bristow-Johnson's audio EQ
  cookbook formulae (see the source for more details).  The Q factor
  selects the shape of the response curve.  Order 1 gives the curves
  as specified in the original document.  Higher orders stack up these
  filters.  Note that an order one biquad filter is equivalent to an
  order two Bessel or Butterworth filter -- compare LpBe2 with LpBu2
  and LpBq1/0.5, for instance.  The auto-adjust option (-a) is useful
  to get the required 50% (~-3dB) points when comparing filters from
  different families like this.

Biquad low-pass and high-pass filters: For a low-pass filter, the
  significant values are Q=0.5, which is the maximum value to give no
  overshoot in the time response, and Q=0.707, which gives the most
  flat-topped frequency response without having a 'lip'.

Biquad band-pass, band-stop, all-pass and peaking filters: For these,
  larger Q values are good -- try up to Q=10 or more.  The peaking
  filter is designed to emphasise a frequency range.  The second value
  in this case is the peak gain in dB.  For example: PkBq1/3/10/0.1

Biquad audio shelving filters: These use a 'shelf slope' parameter
  instead of Q.  S=1 gives the steepest slope without a lip, and lower
  values give lower values of slope.  The second parameter is the gain
  in the affected area in dB.


Filter testing mode
-------------------

Whilst the frequency response display is active, it is possible to
test the filter by passing test signals through it.  Testing mode is
entered by typing 't', then the test-signal spec, and then <Return>.
You exit the mode by simply pressing 't' and then <Return>.  The 'x'
(expand) key may be useful to view any measured points which are off
the top of the display.

Two test signals are provided.  These can be useful for getting a more
realistic view of your filter than the idealised calculated frequency
response (which assumes you always have perfect infinitely-long
sine-waves as input).

The first test signal is a sweeping tone, a sine-wave with linearly
increasing or decreasing frequency.  By passing a smoothly-varying
sine-wave through the filter, you might expect to get out of the other
end a response matching the shape of the response curve for that
frequency range.  However, this is not the case.  As the rate of the
tone's frequency change increases, the shape of the output becomes
more and more distorted.  This is most noticeable in filters that have
a long time-response because different parts of the filter will catch
different frequencies out of the sweeping tone.  Test this by entering
a spec of 's' followed by the rate of change of the tone's frequency
in Hz/sec, either positive or negative (e.g. 's0.1' or 's-1.5').  With
a rate of change of 0 ('s0'), this should give an identical response
to the calculated response.

(Note that the test signals passed to the filter aim to put the target
frequency at the correct centre of the filter time-response, but this
is not always accurate, resulting in a measured response which may be
offset either to the left or right compared to the calculated
response.  The shape will be correct, though, even if it has been
offset by a few Hz.)

The second test signal is a wavelet of a given number of wave periods.
This can give you an idea of how transient signals are handled by the
filter.  Test with a wavelet by using a spec of 'w' plus the length of
the wavelet in wave-periods, for example 'w8', 'w20' or 'w100'.

(Note that the wavelets are formed by applying a Blackman window to a
sine-wave.  The 'length' is the full length of the Blackman window.
For frequencies close to zero, the wavelets can be immensely long, so
the calculation drops out, and the points will be missing from the
display.)

General notes: 

Although I've said 'sine-wave' in the descriptions above, I'm actually
running a complex oscillator through the filters, i.e. two independent
sine-waves 90 degrees out of phase.  This means that I can work with
continuous output values, without having to watch out for maxima,
giving more accurate results.

Also, regarding accuracy: Sweeps are calculated to the 99.9% point of
the filter, i.e. to roughly 3sf.  Wavelets are limited by the
behaviour of the window for very high frequencies.  The program
doesn't stop you looking beyond the limits of the accuracy of the
algorithms, so in the extreme limits you may be examining artifacts of
the analysis methods rather than artifacts of your filter.  In fact,
by zooming in on very small features, you can even get to see
artifacts of the 64-bit floating point format!  Double-check with your
own testing if these things matter to you, or adjust the Fiview code.


TODO
----

Make long impulse-response filter checks time-out after 2 sec each
  filter to make performance similar on different-spec machines.

Clean up remaining JIT run-filter bugs (or drop the JIT option; only 
  gives around 20% speed-up when enabled)

Add FIR filters (hamming, blackman, Tony Fisher's ones)
Probably need to put some loops in the generated example code to 
  handle big FIRs more nicely

Cross-test new generated fid_design code against other types of
  generated example code

Put in -a auto-adjust code for band-pass and band-stop


MAYBE
-----

Maybe put in code to flatten the phase in the pass-band and display
  the equivalent delay.  For LP and HP, it would be possible to
  calculate the slope of the phase at f=0.0 and 0.5 by substituting in a
  small delta and eliminating delta-squared and higher.

Maybe clicking on mini displays shifts within main display
Maybe click on main displays zooms in and out (L + R)
Maybe drag on main display moves display

Maybe add bigger font, and switch automatically to it for larger displays.
Maybe permit specification and display of combined responses,
  e.g. filter1 + filter2, or filter1 adjusted using amplitude modulation.

Maybe give generated process() and setup() calls names including the
  spec, e.g process_LpBu4.  Problems with combined filters, but perhaps
  we could allow these to be labelled, and carry the label over.

";

// END //
