<sect1>
<title>Events</title>

<para>The VPBAPI uses an event driven programming model. There
are two types of events, solicted, and unsolicited. The following
functions deal with events:</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-disable-event">vpb_disable_event()</link></function></member>
<member><function><link linkend="vpb-enable-event">vpb_enable_event()</link></function></member>
<member><function><link linkend="vpb-get-event-mask">vpb_get_event_mask()</link></function></member>
<member><function><link linkend="vpb-set-event-mask">vpb_set_event_mask()</link></function></member>
<member><function><link linkend="vpb-get-event-async">vpb_get_event_async()</link></function></member>
<member><function><link linkend="vpb-get-event-sync">vpb_get_event_sync()</link></function></member>
<member><function><link linkend="vpb-get-event-ch-async">vpb_get_event_ch_async()</link></function></member>
<member><function><link linkend="vpb-get-event-ch-sync">vpb_get_event_ch_sync()</link></function></member>
<member><function><link linkend="vpb-put-event">vpb_put_event()</link></function></member>

</simplelist>

<para>
Solicited events are generated as a response to a previous API
function call. For example, when
<function><link linkend="vpb-play-file-async">vpb_play_file_async()</link></function> is called, a solicited
event of type <function>VPB_PLAYEND</function> is generated when the
file has finished playing.
</para>

<para>
Unsolicited events are generated in response to external
conditions, for example due to a DTMF tone being detected by the card.
</para>

</sect1>

<sect1>
<title>Playing and Recording Audio</title>

<sect2>
<title>Summary of Play Functions</title>

<para>The API play functions are listed below:</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-play-file-sync">vpb_play_file_sync()</link></function></member>
<member><function><link linkend="vpb-play-file-async">vpb_play_file_async()</link></function></member>
<member><function><link linkend="vpb-play-voxfile-sync">vpb_play_voxfile_sync()</link></function></member>
<member><function><link linkend="vpb-play-voxfile-async">vpb_play_voxfile_async()</link></function></member>
<member><function><link linkend="vpb-play-terminate">vpb_play_terminate()</link></function></member>
<member><function><link linkend="vpb-play-buf-start">vpb_play_buf_start()</link></function></member>
<member><function><link linkend="vpb-play-buf-sync">vpb_play_buf_sync()</link></function></member>
<member><function><link linkend="vpb-play-buf-finish">vpb_play_buf_finish()</link></function></member>
<member><function><link linkend="vpb-play-set">vpb_play_set()</link></function></member>
<member><function><link linkend="vpb-play-set-gain">vpb_play_set_gain()</link></function></member>
<member><function><link linkend="vpb-play-get-gain">vpb_play_get_gain()</link></function></member>

</simplelist>

<para>
The VPBAPI supports the playing of WAVE and VOX and AU files. It also
accommodates the playing of buffers from memory via the user defined
play routines. The play functions can be configured to terminate when
a DTMF digit is received using <function><link linkend="vpb-play-set">vpb_play_set()</link></function>.
The play functions may be prematurely stopped using
<function><link linkend="vpb-play-terminate">vpb_play_terminate()</link></function>.  The API provides a
function to alter the VPB audio out levels within the range of -12 to
12 dB (0.1dB resolution). This is accomplished by
<function><link linkend="vpb-play-set-gain">vpb_play_set_gain()</link></function>.
</para>

</sect2>

<sect2>
<title>Summary of Record Functions</title>

<para>The API record functions are listed below:</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-record-file-sync">vpb_record_file_sync()</link></function></member>
<member><function><link linkend="vpb-record-file-async">vpb_record_file_async()</link></function></member>
<member><function><link linkend="vpb-record-voxfile-sync">vpb_record_voxfile_sync()</link></function></member>
<member><function><link linkend="vpb-record-voxfile-async">vpb_record_voxfile_async()</link></function></member>
<member><function><link linkend="vpb-record-terminate">vpb_record_terminate()</link></function></member>
<member><function><link linkend="vpb-record-buf-start">vpb_record_buf_start()</link></function></member>
<member><function><link linkend="vpb-record-buf-sync">vpb_record_buf_sync()</link></function></member>
<member><function><link linkend="vpb-record-buf-finish">vpb_record_buf_finish()</link></function></member>
<member><function><link linkend="vpb-record-set">vpb_record_set()</link></function></member>
<member><function><link linkend="vpb-record-set-gain">vpb_record_set_gain()</link></function></member>
<member><function><link linkend="vpb-record-get-gain">vpb_record_get_gain()</link></function></member>

</simplelist>

<para>
The VPBAPI supports the recording of audio files. It also
accommodates the recording of audio to memory via the user defined
record routines. The record functions can be configured to terminate
when a DTMF digit is received using <function><link linkend="vpb-record-set">vpb_record_set()</link></function>.  The record
functions may be prematurely stopped using <function><link linkend="vpb-record-terminate">vpb_record_terminate()</link></function>.
The API provides a function to alter the VPB audio in levels within
the range of -12 to 12 dB (0.1dB resolution). This is accomplished by
<function><link linkend="vpb-record-set-gain">vpb_record_set_gain()</link></function>.
</para>
</sect2>

<sect2>
<title>Playing Audio</title>

<para>
The API functions for playing audio are divided into two
groups; file-based functions, and buffer-based functions.
</para>

<para>
The file-based play functions are designed to make playing files
straightforward.  These functions support WAVE and AU files sampled at
8 ksamples/s only, playing files that follow the WAVE and AU file
specification including for 16 bit Linear, 8 bit A-Law, 8 bit Mu-Law,
and 4-bit OKI-ADPCM.
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-play-file-sync">vpb_play_file_sync()</link></function></member>
<member><function><link linkend="vpb-play-file-async">vpb_play_file_async()</link></function></member>

</simplelist>

<para>
There are also file-based play functions that support VOX (headerless)
audio files sampled at 8 ksamples/s including; 16 bit Linear, 8 bit A-Law,
8 bit Mu-Law and 4 bit OKI-ADPCM.
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-play-voxfile-sync">vpb_play_voxfile_sync()</link></function></member>
<member><function><link linkend="vpb-play-voxfile-async">vpb_play_voxfile_async()</link></function></member>

</simplelist>

<para>
The buffer-based play functions allow the development of custom play
routines in situations where the file-based functions are
inappropriate, for example, when playing buffers from memory or when
using non WAVE/VOX file formats:
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-play-buf-start">vpb_play_buf_start()</link></function></member>
<member><function><link linkend="vpb-play-buf-sync">vpb_play_buf_sync()</link></function></member>
<member><function><link linkend="vpb-play-buf-finish">vpb_play_buf_finish()</link></function></member>

</simplelist>

</sect2>

<sect2>
<title>Compression (encoding) mode used to store samples</title>

<informaltable frame="all">
<tgroup cols="2">
  <thead>
    <row>
      <entry>Mode</entry>
      <entry>Description</entry>
    </row>
  </thead>
  <tbody>
    <row>
      <entry>VPB_LINEAR</entry>
      <entry>128kbit/s, 16 bit linear, 8kHz sampling rate</entry>
    </row>
    <row>
      <entry>VPB_ALAW</entry>
      <entry>64kbit/s, A-Law companded</entry>
    </row>
    <row>
      <entry>VPB_MULAW</entry>
      <entry>64kbit/s, Mu-Law companded</entry>
    </row>
    <row>
      <entry>VPB_OKIADPCM</entry>
      <entry>32kbit/s, Oki-ADPCM, 4 bit, 8kHz sampling rate</entry>
    </row>
    <row>
      <entry>VPB_OKIADPCM24</entry>
      <entry>24kbit/s, Oki-ADPCM, 4 bit, 6kHz sampling rate</entry>
    </row>
  </tbody>
</tgroup>
</informaltable>
</sect2>

<sect2>
<title>Recording Audio</title>

<para>
The API functions for recording audio are divided into
two groups; file-based functions and buffer-based functions.
</para>

<para>
The file-based record functions are designed to make recording
files straightforward.
The functions support WAVE files sampled at 8 ksamples/s,
recording audio to files that follow the WAVE file layout specification
including 16 bit Linear, 8 bit A-Law, 8 bit Mu-Law and 4-bit OKI-ADPCM.
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-record-file-sync">vpb_record_file_sync()</link></function></member>
<member><function><link linkend="vpb-record-file-async">vpb_record_file_async()</link></function></member>

</simplelist>

<para>
There are also file-based record functions that support VOX
audio files sampled at 8 ksamples/s including; 16 bit Linear, 8 bit
A-Law, 8 bit Mu-Law and 4 bit OKI-ADPCM.
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-record-voxfile-sync">vpb_record_voxfile_sync()</link></function></member>
<member><function><link linkend="vpb-record-voxfile-async">vpb_record_voxfile_async()</link></function></member>

</simplelist>

<para>
The user definedbuffer-based record functions allow the development
of custom record routines in situations where the utility functions are
inappropriate, for example, when recording buffers to memory or when using
non WAVE/VOX file formats:
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-record-buf-start">vpb_record_buf_start()</link></function></member>
<member><function><link linkend="vpb-record-buf-sync">vpb_record_buf_sync()</link></function></member>
<member><function><link linkend="vpb-record-buf-finish">vpb_record_buf_finish()</link></function></member>

</simplelist>
</sect2>
</sect1>

<sect1>
<title>DTMF and Programmable Tone Generation</title>

<para>
The following functions support tone generation on the
VPB:
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-dial-async">vpb_dial_async()</link></function></member>
<member><function><link linkend="vpb-dial-sync">vpb_dial_sync()</link></function></member>
<member><function><link linkend="vpb-settone">vpb_settone()</link></function></member>
<member><function><link linkend="vpb-gettone">vpb_gettone()</link></function></member>

</simplelist>

<para>
Tones (including DTMF) tones are generated on a channel using the
<function><link linkend="vpb-settone">vpb_settone()</link></function> function.  All of the standard DTMF
tones are defined at initialization.  Other user defined tones can be
programmed at any time using the <function><link linkend="vpb-settone">vpb_settone()</link></function>
function.  The standard DTMF tones can also be reprogrammed using the
<function><link linkend="vpb-settone">vpb_settone()</link></function> function.  The tone generator
parameters are constant across all VPB channels, they are not
programmable on a channel by channel, or board by board basis.  Up to
10 programmable tones can be defined, giving a total of 26 tones
including the standard DTMF tones.  Each tone can consist of up to 3
frequency components, each with independent amplitude, specified in dB
with respect to the overload level of 0dB.  There are limits in the
tone generator parameters.  Attempting to program a tone outside of
these limits will generate an error.
</para>
</sect1>

<sect1>
<title>Tone Detection</title>

<para>
The following functions support programmable tone detection:
</para>

<simplelist type="horiz" columns="1">

<member><function><link linkend="vpb-settonedet">vpb_settonedet()</link></function></member>
<member><function><link linkend="vpb-gettonedet">vpb_gettonedet()</link></function></member>
<member><function><link linkend="vpb-debug-tonedet">vpb_debug_tonedet()</link></function></member>

</simplelist>

<para>
When a tone is detected, a <function>VPB_TONEDETECT</function> event
is placed on the event queue with the tone identifier placed in the
data element of the event structure.  There are 3 pre-defined tones,
<function>VPB_DIAL</function> (dial tone),
<function>VPB_RINGBACK</function> (ringback), and
<function>VPB_BUSY</function> (busy tone). These are configured for
standard tones and may be redefined if desired to suit the
actual switch to which the VPB is connected.  Up to
<function>VPB_MD</function> (a <function>#define</function> in
<filename>vpbapi.h</filename>) tone detectors can be defined for each channel
of each VPB. Counting the 3 pre-defined tones,
<function>VPB_MD-3</function> new user defined tones are available for
the user, or the pre-defined tones may be redefined to give a total of
<function>VPB_MD</function> user defined tones. To redefine a
pre-defined tone, just specify the pre-defined tone identifier in the
tone_id parameter of the <function>VPB_DETECT</function> structure when
programming the tone.
</para>

<para>
Note: The <function>VPB_MD</function> (<function>#define</function> in
<filename>vpbapi.h</filename>) is set by Voicetronix and should not be
modified by the user. Up to ten programmable tones (including the
pre-defined tones) are available for the user.  The tone detectors of
each channel are independent of the tone detectors of other
channels. Thus each channel must be programmed independently with the
<function><link linkend="vpb-settonedet">vpb_settonedet()</link></function> API function.
</para>

<sect2>
<title>Programming the Tone Detectors</title>

<para>
Tone detectors (either DIAL, BUSY, RINGBACK, GRUNT, or user [5..9] tone 
detectors) can be programmed at driver start up using the VPB_TONE env. 
variable.  The main reason for this feature is to allow users to program the 
busy tone detector for different PBX models without having to modify and recompile
any code.
</para>

<para>
The format of the VPB_TONE env. variable is described in
<filename>src/envtone.cpp</filename>. 
</para>

<para>
The tone detectors can also be programmed using the VPBAPI function
calls.  For more information on this and tone detection in general please see
the next section.
</para>

<para>
To determine the parameters of a tone:
</para>

<orderedlist>

  <listitem><para> Sample the tone using
    <filename>unittest/recwav</filename>.  For example to sample the
    busy tone, dial the port, start <filename>recwav</filename>, then
    hangup the phone.  To sample dial tone just run
    <filename>recwav</filename> without dialling the port from another
    extension.  Run <filename>recwave</filename> for about 30 seconds
    on pulsed tones so that you get at least 10 repetitions - this
    helps later with testing.  </para></listitem>

  <listitem><para>
    Use a waveform editor to view the tone and determine it's
    frequency and on-time (on-time is only valid for pulsed tones such
    as busy only, dial tones usually stay on).  I use a Windows
    shareware editor called <ulink
    url="http://www.voicetronix.com">Goldwave</ulink>.  You can
    determine the frequency of the tone in Goldwave by clicking on the
    waveform window in the "Device Controls window", this will give
    you a spectral view of the tone.  Each division is 400Hz.  There
    may be similar tools available for Linux.
  </para></listitem>

  <listitem><para>
    For a pulsed tone, determine the frequency and on-time.  For continuous
    tone such as dial, just the frequency is required.
  </para></listitem>

  <listitem><para>
    To test your tone detector, the
    <filename>unittest/tonedebug</filename> program is useful.  This
    program can play your sampled tone, while at the same time it
    tries to detect the tone using the parameters you have determined.
    These parameters can be entered on the command line of tonedebug,
    so testing variations of the tone detector parameters is easy.
    Note that this program must run without <emphasis>any</emphasis>
    phone lines connected to the card - it replays the tone you
    sampled, while simultaneously sampling the same signal to the
    prototype tone detector you are testing.
  </para></listitem>

  <listitem><para>
    Try setting the bandwidth to 100Hz, if that doesn't work, try 200Hz.
  </para></listitem>

  <listitem><para>
    Once you are happy with the tone detector (for example, it detects
    all 10 repetitions of the tones you sampled), you can then set the
    env. variable to describe the tone, and run your main application.
  </para></listitem>

</orderedlist>

<sect3>
<title>Examples</title>

<sect4>
<title>Dial tone</title>

<para>
The frequency is 500Hz, and we select a bandwidth of 100Hz. We
would like the tone detector to "fire" after 1 second (1000ms) of continuous 
dial tone. The dial tone we sampled with <filename>recwav</filename> is in the file <filename>mydial.wav</filename>.
</para>

<para>
In the <filename>unittest</filename> dir:
</para>

<literallayout><prompt>$ </prompt><userinput> ./tonedebug -c 500 100 1000 -w mydial.wav -t dial</userinput></literallayout>

<para>
which will produce:
</para>

<screen>
[00] Tone Detect: Dial
[00] Play End
</screen>
</sect4>

<sect4>
<title>Busy tone</title>

<para>
The frequency is 425Hz, and we select a bandwidth of 200Hz.
By inspecting the wave file we determine that this pulsed tone is on for 375ms.
The wave file is called <filename>mybusy.wav</filename>.
</para>

<literallayout><prompt>$ </prompt><userinput> ./tonedebug -p 425 200 375 -w mybusy.wav -t busy</userinput></literallayout>

<para>
which will produce something like:
</para>

<screen>
[00] Tone Detect: Grunt
[00] Tone Detect: Busy
[00] Tone Detect: Busy
[00] Tone Detect: Busy
[00] Play End
</screen>

<para>
In this case, all three busy tones sampled were detected OK.  The "grunt" tone 
is a special tone detector that just senses energy on the line.
</para>

<para>
To then set the busy tone detector using an env. variable (bash shell):
</para>

<literallayout><prompt>$ </prompt><userinput> export VPB_TONE=BUSY,P,425,200,375 </userinput></literallayout>

<para>
See also <filename>src/envtone.cpp</filename> for more information.
</para>
</sect4>
</sect3>

</sect2>

<sect2>
<title>More Detail on Programming the Tone Detectors</title>

<para>
The tone detection algorithm is split into two phases.  The first
phase checks an incoming signal to determine if its signal parameters
fit the templates defined in the tone detector, for example, the
frequency, bandwidth, level, and signal to noise ratio (SNR). The
second phase looks at the on-off timing of the signal, or cadence
information. If both the signal parameters and the cadence parameters
match, an event is posted.
</para>

<para>
Each programmable tone has a unique identifier, i.e. a 16 bit integer
that is placed in the data element of the event when the tone is
detected. The value of the tone identifier is not important, as long
as it is unique. If <function><link linkend="vpb-settonedet">vpb_settonedet()</link></function> is called
with a non-unique identifier (one which has been used before), then
that programmable tone is redefined. If
<function><link linkend="vpb-settonedet">vpb_settonedet()</link></function> is called with a unique
identifier (one which has not been used before), then a new
programmable tone is defined.
</para>

<para>
The structure <function>VPB_DETECT</function> is used to define a
programmable tone. Single or dual frequencies can be specified, each
with independent frequency, amplitude, and bandwidth. In addition, the
allowable twist for dual tones (difference in level between the two
tones) can be defined.  Attempting to define a tone outside of the
tone detector limits will cause an error.
</para>

</sect2>

<sect2>
<title>Signal Detection Algorithm</title>

<para>
For a single frequency tone to pass the signal processing
phase, the following conditions must be true:
</para>

<orderedlist>

<listitem><para>
The level of the tone in the band specified by the
frequency (freq1) and bandwidth (bandwidth1) must be above the minimum
level (minlevel1). 
</para></listitem>

<listitem><para>
The signal energy must be greater than the rest of the energy
in the received signal by the specified signal to noise ratio (snr).
</para></listitem>

<listitem><para>
If the above conditions are met, then the signal is declared
detected and is passed to the cadence detection stage for cadence analysis.
For a dual frequency tone to pass the signal processing
phase, the following conditions must be true:
</para></listitem>

<listitem><para>
The level of the first frequency component in the band specified
by the frequency (freq1) and bandwidth (bandwidth1)
must be above the minimum level (minlevel1).
</para></listitem>

<listitem><para>
The level of the second frequency component in the band specified
by the frequency (freq2)
and bandwidth (bandwidth2)
must be above the minimum level (minlevel2).
</para></listitem>

<listitem><para>
The total signal energy in both bands must be greater than
the rest of the energy in the received signal by the specified signal to noise
ratio (snr).
</para></listitem>

<listitem><para>
The difference in the energies of the two frequency components
must be within the allowed twist.
</para></listitem>

</orderedlist>

<para>
If the above conditions are met, then the signal is declared
detected and is passed to the cadence detection stage for cadence analysis.
</para>

</sect2>

<sect2>
<title>Cadence Detection Algorithm</title>

<para>
The cadence detection parameters of the tone detector are defined by
constructing a state machine for each tone detector. The state machine
is defined by a state transition table (stran), and the number of
states (nstates).  The state transition table consists of an array of
<function>VPB_STRAN</function> structures.  The state machine begins
in state 0 and progresses to the next state when the state transition
requirements are met for that state. When the final state transition
occurs, an event of type <function>VPB_TONEDETECT</function> is posted
on the API event queue. A maximum of <function>VPB_MS</function>
(<function>#define</function> in <filename>vpbapi.h</filename>) cadence states
are allowed for each state machine.
</para>

<para>
There are three types of state transitions:
</para>

<simplelist type="horiz" columns="1">

<member>
<function>VPB_TIMER</function>.  A state transition
occurs when no change (transition) in the signal occurs for the fire time (<function>tfire</function>) in milliseconds.
If a transition occurs before time <function>tfire</function>, the state machine is reset
to state 0.  The <function>VPB_TIMER</function> transition provides a
way to measure the on time of signals without cadence, for example
continuous dial tones.  
</member>

<member>
<function>VPB_DELAY</function>. It waits the desired time, <function>tfire</function>
ms and goes to the next state. The <function>VPB_DELAY</function>
transition provides a way to wait a desired time irrespective of any signal
transitions.
</member>

<member>
<function>VPB_RISING</function>. A state transition occurs on the
rising edge of the signal detection, that is, when the signal goes
from a non-detected to detected state. The state transition occurs if
the time spent in this state is between the minimal (<function>tmin</function>) and maximum (<function>tmax</function>) time in milliseconds. If at the
rising edge the time spent in this state is not between <function>tmin</function> and <function>tmax</function>
ms, the state machine is reset to state 0.  If <function>tmin</function> and <function>tmax</function> are both
set to 0, then a state transition occurs on the rising edge of the
signal, regardless of the time spent in this state.  The
<function>VPB_RISING</function> transition provides a way to determine
how long the signal was off.
</member>

<member>
<function>VPB_FALLING</function>. A state transition occurs on the
falling edge of the signal detection, that is when the signal goes
from a detected to non-detected state. The state transition occurs if
the time spent in this state is between <function>tmin</function> and <function>tmax</function> ms.  If at the
falling edge the time spent in this state is not between <function>tmin</function> and <function>tmax</function>
ms, the state machine is reset to state 0.  If <function>tmin</function> and <function>tmax</function> are both
set to 0, then a state transition occurs on the falling edge of the
signal, regardless of the time spent in this state.  The
<function>VPB_FALLING</function> transition provides a way to
determine how long the signal was on.
</member>

</simplelist>
</sect2>

<sect2>
<title>Programmable Tone Detector Tips</title>

<para>
The cadence state machine approach has the advantage that
non-periodic or variable cadences may be detected, for example a tone that
has a long on period, then a short on period.
To detect several cycles of a periodic cadence pattern,
for example 3 on/off cycles of a busy tone, just repeat the cadence state
detector rising and falling edge transitions the desired number of times,
up to the <function>VPB_MS</function> (<function>#define</function> in
<function>vpbapi.h</function>) limit.
</para>

<para>
When designing/debugging a tone detector, start with a
simple cadence detector, for example just a single rising edge state. Adjust
the signal detection parameters first, then add and test the extra cadence
states one at a time. This will identify any problems with the last cadence
state added. Don't forget to modify the
nstates parameter in the <function>VPB_DETECT</function> structure
as extra states are added.
</para>

<para>
When designing/debugging a tone detector, start with wide bandwidths
(several hundred Hz), and low level thresholds (say -40 dB), then
gradually tighten (reduce bandwidth, increase level) these parameters
to increase the robustness of the tone detector.  Amplitude modulated
signals have wider bandwidths than pure sinusoids, and their
amplitudes move up and down with the modulation frequency. Amplitude
modulated signals may therefore need lower level thresholds than
unmodulated tones. As a rule of thumb, use a bandwidth about four
times as wide as the modulating frequency, for example, 100 Hz for a
25 Hz modulating frequency. The level threshold may need to be very
low to detect the signal through the low level periods, so try -40 dB
as a starting point for the level parameters.
</para>

</sect2>

<sect2>
<title>Programmable Tone Detector Examples</title>

<sect3>
<title>Continuous dial tone at 425 Hz, amplitude
modulated at 25 Hz</title>

<para>
This discussion refers to the <function>toned_dial</function>
variable below.
</para>

<para>
This tone is amplitude modulated at 25 Hz, which spreads
the bandwidth approximately 25 Hz either side of the main frequency component.
A bandwidth of 100 Hz is used to be sure that all of the dial tone energy
is captured, although only 50 Hz is strictly necessary. The level of amplitude
modulated signals can also be quite low (it varies up and down with the
modulating signal), so a low amplitude threshold of -40dB is used. The
tone contains only a single frequency component so the 2nd frequency
parameters are set to 0, which instructs the tone detector software to
ignore the 2nd frequency.
</para>

<para>
The signal to noise ratio (SNR) was set to 10 dB so that
the detector requires most of the energy in the signal to be contained
in the 100 Hz bandwidth. This helps to reduce false triggering, for example
by a speech signal that may have energy around 400 Hz.
</para>

<para>
There are two cadence states specified. The first looks
for a rising edge in the signal detection logic. No time parameters are
specified, so only the rising edge (from non-detected to detected signal
condition) is required to move the state machine to the second state.
</para>

<para>
The second state is a <function>VPB_TIMER</function> state. This timer
"fires" when the signal has been detected for 2000 ms.  If the signal
disappears in this time, the state machine is reset to the first state
and no event is posted. If the signal continues uninterrupted for 2000
ms, an event is posted to the API event queue and the state machine
resets itself to state 0. The event will contain
<function>VPB_DIAL</function> in the data member of the
<function>VPB_EVENT</function> structure.
</para>

<para>
Note that the timer state provides an additional level of "filtering",
as the signal must be continuous and uninterrupted for 2000 ms. Any
non-valid signals are unlikely to meet the signal detection conditions
for this time, and will be discarded by the state machine.
</para>

<example>
<title>toned_dial for 425Hz continuous dial tone, modulated at 25Hz</title>
<programlisting role="C">

static VPB_DETECT toned_dial = {
        2,        // number of cadence states
        VPB_DIAL, // tone id
        1,        // number of tones
        425,      // freq1
        100,      // bandwidth1
        0,        // freq2, N/A
        0,        // bandwidth2, N/A
        -40,      // level1
        0,        // level2, N/A
        0,        // twist, N/A
        10,       // SNR
        40,       // glitch duration 40ms

        RISING,   // state 0
        0,
        0,
        0,

        TIMER,    // state 1
        2000,
        0,
        0
};

</programlisting>
</example>

</sect3>

<sect3>
<title>Austel Busy Tone 425 Hz or 400 Hz, 375ms on, 375 ms off
</title>

<para>
This discussion refers to the <function>toned_austel_busy</function>
variable below.
</para>

<para>
The Austel busy tone has two possible frequencies, 400 or 425 Hz, so a
bandwidth of 100 Hz has been used to make sure both possibilities are
within the bandwidth of the signal detector. As the signal is a single
unmodulated tone, the amplitude will be relatively stable, so we can
set a fairly high cut off level of -20 dB.  The cadence state machine
has 3 states, which detect a single on/off cycle of the busy tone. The
first state detects the first rising edge, with no time
parameters. The second state waits for the falling edge, and checks
that the signal on time was between 300 and 450 ms. The third state
then waits for the next rising edge, and checks if its off time was
between 300 and 450 ms. If so, then a
<function>VPB_AUSTEL_BUSY</function> event is posted to the API
queue. If any of these conditions fail then the state machine resets
and no events are generated.
</para>

<example>
<title>Austel busy tone</title>
<programlisting role="C">

static VPB_DETECT toned_austel_busy = {
        3,               // number of cadence states
        VPB_AUSTEL_BUSY, // tone id
        1,               // number of tones
        425,             // freq1
        100,             // bandwidth1
        0,               // freq2, N/A
        0,               // bandwidth2:N/A
        -20,             // level1
        0,               // level2, N/A
        0,               // twist:N/A
        10,              // SNR: 10dB
        40,              // glitch duration 40ms
        VPB_RISING,      // state
        0
        0,
        0,
        0,
        VPB_FALLING,     // state 1
        0,
        300,
        450,
        VPB_RISING,      // state 2
        0,
        300,
        450,
};

</programlisting>
</example>

</sect3>

<sect3>
<title>DTMF tone detection</title>

<para>
This example demonstrates the ability of the programmable tone
detector to detect tones with two frequency components, in this case
the DTMF tone for 1, composed of 697 Hz, and 1209 Hz. The variable
<function>toned_dtmf1</function> below illustrates the configuration
for this tone.
</para>

<para>
The signal detection parameters are straightforward, both
frequencies have the same level thresholds. The twist parameter
specifies the maximum permissible difference in the magnitudes of the
two frequency components of the tones, in this case it is 10 dB.  The
cadence state machine looks for a rising edge, then the tone must be
present for a minimum of 100 ms before a
<function>VPB_TONEDETECT</function> event with the data member set to
DTMF_1 (user #defined to a unique tone identifier) is posted.
</para>

<example>
<title>DTMF tone detector</title>
<programlisting role="C">

static VPB_DETECT toned_dtmf1 = {
        2,          // number of cadence states
        DTMF_1,     // tone id
        2,          // number of tones
        697,        // f1: centre frequency
        100,        // bw1: bandwidth
        1209,       // f2: centre frequency
        100,        // bw2: bandwidth
        -20,        // A1: -20 dBm0
        -20,        // A2: -20 dBm0
        10,         // twist: 10 dB
        10,         // SNR: 10 dB
        40          // glitch duration 40ms

        VPB_RISING, // state 0
        0,
        0,
        0,

        VPB_TIMER,  // state 1
        100,
        0,
        0
};

</programlisting>
</example>

</sect3>

<sect3>
<title>Example 4 - Grunt Detector used to detect wide band
signals such as voice</title>

<para>
This discussion refers to the <function>toned_grunt</function> variable below.
</para>

<para>
Voice signals have a wide band signal characteristic, with most of the
energy located between 50-2000Hz. The grunt detector looks for wide
band energy between 500Hz and 3500Hz. The lower frequency band (500Hz)
was selected as not to overlap with other telephony signals, such as
dial and busy tones which have their energy centred around 400Hz.  The
cadence state machine has 2 states to detect a wideband signal. The
first state waits for 1 second, ignoring any signal transitions.  The
second state checks for a rising edge in the signal with an off time
between 0-40 ms. If so, then a <function>VPB_GRUNT</function> event is
posted to the API queue. If any of these conditions fail then the
state machine resets and no events are generated.
</para>

<example>
<title>DTMF tone detector</title>
<programlisting role="C">

static VPB_DETECT toned_grunt = {
        2,           // number of cadence states
        VPB_GRUNT,   // tone id
        1,           // number of tones
        2000,        // freq1
        3000,        // bandwidth1
        0,           // freq2, N/A
        0,           // bandwidth2: N/A
        -40,         // level1 (-40 dB)
        0,           // level2, N/A
        0,           // twist: N/A
        0,           // SNR: N/A
        40           // glitch duration 40ms

        VPB_DELAY,   // state 0
        1000,
        0,
        0,

        VPB_RISING,  // state 1
        0,
        40,
        0
};

</programlisting>
</example>

</sect3>
</sect2>

</sect1>

<sect1>
<title>Automated Tone Training</title>

<sect2>
<title>Introduction</title>
<para>
To make programming the tone detectors easier, an automated tone
training application, <function>tonetrain</function>, has been
developed, and is included in the vpb-driver software.
</para>

<para>
Using this application, tone training is a three step process:
</para>

<orderedlist>    

  <listitem><para>Record a sample of the tone.</para></listitem>
  <listitem>
    <para>Run <function>tonetrain</function> to analyse the
    sample and determine suitable tone detector parameters.</para>
  </listitem>
  <listitem>
    <para>Test the tone detector parameters on your recorded tone</para>
  </listitem>
</orderedlist>    

</sect2>

<sect2>
<title>Compiling</title>

  <para>
  First ensure you have already compiled the driver
  (see <function>README</function> in the root directory of vpb-driver).
  </para>

  <literallayout><prompt>$</prompt><userinput>cd tonetrain</userinput></literallayout>

  <literallayout><prompt>$</prompt><userinput>./configure</userinput></literallayout> 
     
  <literallayout><prompt>$</prompt><userinput>make</userinput></literallayout> 

</sect2>

<sect2>
<title>Tutorial</title>

<sect3>
<title>Setup</title>

<para>
To sample tones you will need a Voicetronix card, for example an OpenLine4 or
OpenSwitch12 card.  This card should be installed and tested.  You
will also need to connect a port of the Voicetronix card to the
telephone line that you wish to train tones for.  Different telephone
line and PBXs tend to generate different tones.  A second phone line
or mobile (cell) telephone is also useful.
</para>

<para>
Make sure you have compiled, installed and tested the Voicetronix
driver.  You will also need to have compiled
<function>recwav</function> and <function>tonedebug</function>, both
located in the unittest directory.
</para>
</sect3>
<sect3>
<title>
Sample files
</title>
<para>
There are some sample files in the tonetrain sub-directory.
They are:
<simplelist type="horiz" columns="1">
<member>400-c-tone.wav	- a continous tone of 400Hz</member>
<member>600-c-tone.wav  - a continous tone of 600Hz</member>
<member>hs-dialtone.wav  - dial tone from our PBX</member>
<member>hs-ringback.wav - ring back tone from our local exchange</member>
</simplelist>

Using these files you can run <function>tonetrainer</function> and then 
plug the results back into <function>tonedebug</function> (this requires 
a Voicetronix board)
</para>
</sect3>

<sect3>
<title>Dial Tone Training Example</title>

<para>
To record a sample, perform this command from the
<function>unittest</function> directory:

<literallayout><prompt>$ </prompt><userinput> ./recwav dialtone.wav 1 10</userinput></literallayout> 

This will record 10 seconds of signal on port 1 or the Voicetronix
card.  Before recording, <function>recwav</function> takes the line
off hook, which will cause dial tone to be generated by your exchange
of PBX.  If your telephone line is connected to a different port,
change the second argument.
</para>

<para>
It is a very good idea to check that the sample file is of good
quality, and contains only the tone to be trained.  You can play back
the tone using <function>playwav</function>, or using a suitable command line
or GUI utility.
</para>

<para>
If the sample file is of poor quality, then the automated tone
training process will fail.  It must contain just the tone sample to
be trained, for example no human speech or other tones.
</para>

<para>
Now to determine the tone parameters, perform this command:
<literallayout><prompt>$ </prompt><userinput> tonetrain/tonetrain -e -w dialtone.wav </userinput></literallayout>

The <function>-e</function> option specifies the environment variable output
format, the <function>-w WaveFile</function> specifies a wave file input
format.
</para>

<para>
You should get a result like this:
<screen>
Environment variable format result:
export VPB_TONE=5,C,421,100,2000
</screen>
</para>
<para>
The arguments to the Environment variables are:
<literallayout><userinput> export VPB_TONE=&lt;Tone ID&gt;,&lt;Tone Type&gt;,&lt;Tone Frequency1&gt;,&lt;{Type dependant}...&gt;</userinput></literallayout>
</para>
<para>
Now perform this command to set the environment variable, note that we have changed the Tone ID from 5 to DIAL:
<literallayout><prompt>$ </prompt><userinput>export VPB_TONE=DIAL,C,421,100,2000</userinput></literallayout>
This environment variable is read by the vpb driver when it starts.
The driver uses this information to configure the tone detector to
recognise the tone you have just trained.  For more information on the
tone detector parameters (and how to set them) please see the previous section.
</para>

<para>
There are several other output formats for
<function>tonetrain</function>, see the command line help for more information.
</para>

<para>
After training, you can then test the tone detector using <function>tonedebug</function>.
First, disconnect your telephone line from the Voicetronix
card. Then:

<literallayout><prompt>$ </prompt><userinput>./tonedebug -e -w dialtone.wav</userinput></literallayout>
<screen>
Using Environment...
Note: -w option used for testing tone detector based
on wave files echoed from tx->rx side of hybrid -
make sure no telephone line connected to port 1!
[00] Record fifo overflow
[00] Tone Detect: Dial
[00] Play End
</screen>
</para>

<para>
As with <function>tonetrain</function>, <function>-e</function>
specifies the environment variable output format, the <function>-w
WaveFile</function> option specifies wave file input format for the
sample used to test the tone detector.
</para>
</sect3>

<sect3>
<title>Ringback Tone Example</title>

<para>
Ringback is the tone you  hear in your telephone
handset when the destination phone is ringing.  It starts just after
dialling and stops when the destination phone is answered.
</para>

<para>
To record a sample, you will to have a destination number that 
will not get answered and is not busy! Again we will use the
<function>recwav</function> application:

<literallayout><prompt>$ </prompt><userinput>./recwav ringback.wav 1 10 --dial ,,555</userinput></literallayout>

This example assumes that the destination number you are calling is
555 (just like the movies).  The commas generate a 1 second pause in
the dialling, which is useful as some PBXes and exchanges like pauses
before (and during dialling).  You should hear the phone at the
destination number (in this case 555) ringing during the record
process.

</para>

<para>
If you don't hear the destination phone ringing, then there may have
been a problem dialling.  Investigate and correct this before
proceeding.
</para>

<para>
As with the dial tone example, it is a very good idea to listen to the
recorded sample to ensure it contains the correct ringback tone sample
before proceeding with the training stage.
</para>

<para>
You can then process it through <function>tonetrain</function> and 
<function>tonedebug</function> as before:
<literallayout><prompt>$ </prompt><userinput> tonetrain/tonetrain -e -w ringback.wav </userinput></literallayout>
<screen>
Environment variable format result:
export VPB_TONE=5,P,453,100,1690
</screen>
<literallayout><prompt>$ </prompt><userinput>export VPB_TONE=RINGBACK,P,453,100,1690</userinput></literallayout>
<literallayout><prompt>$ </prompt><userinput>./tonedebug -e -w ringback.wav</userinput></literallayout>
<screen>
Using Environment...
Note: -w option used for testing tone detector based
on wave files echoed from tx->rx side of hybrid -
make sure no telephone line connected to port 1!
[00] Record fifo overflow
[00] Tone Detect: Ringback
[00] Tone Detect: Ringback
[00] Tone Detect: Ringback
[00] Play End
</screen>
</para>

</sect3>

<sect3>
<title>Busy Tone Example</title>

<para>
To record a sample, you will to have a destination number that 
will be busy and wont go to voice mail (you could use the 
number that you are calling from). Again we will use the 
<function>recwav</function> application:

<literallayout><prompt>$ </prompt><userinput>./recwav busy.wav 1 10 --dial ,,555</userinput></literallayout>
</para>

<para>
You can then run it through <function>tonetrain</function> and 
<function>tonedebug</function> as before:
<literallayout><prompt>$ </prompt><userinput> tonetrain/tonetrain -e -w busytone.wav </userinput></literallayout>
<screen>
Environment variable format result:
export VPB_TONE=5,P2,421,100,1000
</screen>
<literallayout><prompt>$ </prompt><userinput>export VPB_TONE=BUSY,P2,421,100,1000</userinput></literallayout>
<literallayout><prompt>$ </prompt><userinput>./tonedebug -e -w busytone.wav</userinput></literallayout>
<screen>
Using Environment...
Note: -w option used for testing tone detector based
on wave files echoed from tx->rx side of hybrid -
make sure no telephone line connected to port 1!
[00] Record fifo overflow
[00] Tone Detect: Busy
[00] Tone Detect: Busy
[00] Tone Detect: Busy
[00] Play End
</screen>
</para>
</sect3>

</sect2>

</sect1>

