Voicetronix Programming Guide
<<< Previous |  | Next >>>

# Tone Detection

The following functions support programmable tone detection:

`vpb_settonedet()`
`vpb_gettonedet()`
`vpb_debug_tonedet()`

When a tone is detected, a `VPB_TONEDETECT` 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, `VPB_DIAL` (dial tone), `VPB_RINGBACK` (ringback), and `VPB_BUSY` (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 `VPB_MD` (a `#define` in `vpbapi.h`) tone detectors can be defined for each channel of each VPB. Counting the 3 pre-defined tones, `VPB_MD-3` new user defined tones are available for the user, or the pre-defined tones may be redefined to give a total of `VPB_MD` user defined tones. To redefine a pre-defined tone, just specify the pre-defined tone identifier in the tone_id parameter of the `VPB_DETECT` structure when programming the tone.

Note: The `VPB_MD` (`#define` in `vpbapi.h`) 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 `vpb_settonedet()` API function.

## Programming the Tone Detectors

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.

The format of the VPB_TONE env. variable is described in `src/envtone.cpp`.

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.

To determine the parameters of a tone:

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

2. 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 Goldwave. 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.

3. For a pulsed tone, determine the frequency and on-time. For continuous tone such as dial, just the frequency is required.

4. To test your tone detector, the `unittest/tonedebug` 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 any 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.

5. Try setting the bandwidth to 100Hz, if that doesn't work, try 200Hz.

6. 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.

### Examples

#### Dial tone

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 `recwav` is in the file `mydial.wav`.

In the `unittest` dir:

`$` `./tonedebug -c 500 100 1000 -w mydial.wav -t dial`

which will produce:

    [00] Tone Detect: Dial
    [00] Play End

#### Busy tone

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 `mybusy.wav`.

`$` `./tonedebug -p 425 200 375 -w mybusy.wav -t busy`

which will produce something like:

    [00] Tone Detect: Grunt
    [00] Tone Detect: Busy
    [00] Tone Detect: Busy
    [00] Tone Detect: Busy
    [00] Play End

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.

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

`$` `export VPB_TONE=BUSY,P,425,200,375`

See also `src/envtone.cpp` for more information.

## More Detail on Programming the Tone Detectors

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.

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 `vpb_settonedet()` is called with a non-unique identifier (one which has been used before), then that programmable tone is redefined. If `vpb_settonedet()` is called with a unique identifier (one which has not been used before), then a new programmable tone is defined.

The structure `VPB_DETECT` 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.

## Signal Detection Algorithm

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

1. The level of the tone in the band specified by the frequency (freq1) and bandwidth (bandwidth1) must be above the minimum level (minlevel1).

2. The signal energy must be greater than the rest of the energy in the received signal by the specified signal to noise ratio (snr).

3. 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:

4. 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).

5. 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).

6. 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).

7. The difference in the energies of the two frequency components must be within the allowed twist.

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

## Cadence Detection Algorithm

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 `VPB_STRAN` 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 `VPB_TONEDETECT` is posted on the API event queue. A maximum of `VPB_MS` (`#define` in `vpbapi.h`) cadence states are allowed for each state machine.

There are three types of state transitions:

`VPB_TIMER`. A state transition occurs when no change (transition) in the signal occurs for the fire time (`tfire`) in milliseconds. If a transition occurs before time `tfire`, the state machine is reset to state 0. The `VPB_TIMER` transition provides a way to measure the on time of signals without cadence, for example continuous dial tones.
`VPB_DELAY`. It waits the desired time, `tfire` ms and goes to the next state. The `VPB_DELAY` transition provides a way to wait a desired time irrespective of any signal transitions.
`VPB_RISING`. 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 (`tmin`) and maximum (`tmax`) time in milliseconds. If at the rising edge the time spent in this state is not between `tmin` and `tmax` ms, the state machine is reset to state 0. If `tmin` and `tmax` 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 `VPB_RISING` transition provides a way to determine how long the signal was off.
`VPB_FALLING`. 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 `tmin` and `tmax` ms. If at the falling edge the time spent in this state is not between `tmin` and `tmax` ms, the state machine is reset to state 0. If `tmin` and `tmax` 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 `VPB_FALLING` transition provides a way to determine how long the signal was on.

## Programmable Tone Detector Tips

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 `VPB_MS` (`#define` in `vpbapi.h`) limit.

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 `VPB_DETECT` structure as extra states are added.

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.

## Programmable Tone Detector Examples

### Continuous dial tone at 425 Hz, amplitude modulated at 25 Hz

This discussion refers to the `toned_dial` variable below.

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.

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.

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.

The second state is a `VPB_TIMER` 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 `VPB_DIAL` in the data member of the `VPB_EVENT` structure.

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.

Example 4. toned_dial for 425Hz continuous dial tone, modulated at 25Hz

    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
    };

### Austel Busy Tone 425 Hz or 400 Hz, 375ms on, 375 ms off

This discussion refers to the `toned_austel_busy` variable below.

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 `VPB_AUSTEL_BUSY` event is posted to the API queue. If any of these conditions fail then the state machine resets and no events are generated.

Example 5. Austel busy tone

    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,
    };

### DTMF tone detection

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 `toned_dtmf1` below illustrates the configuration for this tone.

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 `VPB_TONEDETECT` event with the data member set to DTMF_1 (user #defined to a unique tone identifier) is posted.

Example 6. DTMF tone detector

    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
    };

### Example 4 - Grunt Detector used to detect wide band signals such as voice

This discussion refers to the `toned_grunt` variable below.

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 `VPB_GRUNT` event is posted to the API queue. If any of these conditions fail then the state machine resets and no events are generated.

Example 7. DTMF tone detector

    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
    };

<<< Previous | Home | Next >>>
DTMF and Programmable Tone Generation |  | Automated Tone Training