Documentation

# expander

Dynamic range expander

## Description

The `expander` System object™ performs dynamic range expansion independently across each input channel. Dynamic range expansion attenuates the volume of quiet sounds below a given threshold. It uses specified attack, release, and hold times to achieve a smooth applied gain curve. Properties of the `expander` System object specify the type of dynamic range expansion.

To perform dynamic range expansion:

1. Create the `expander` object and set its properties.

2. Call the object with arguments, as if it were a function.

## Creation

### Syntax

``dRE = expander``
``dRE = expander(thresholdValue)``
``dRE = expander(thresholdValue,ratioValue)``
``dRE = expander(___,Name,Value)``

### Description

````dRE = expander` creates a System object, `dRE`, that performs dynamic range expansion independently across each input channel.```
````dRE = expander(thresholdValue)` sets the Threshold property to `thresholdValue`.```
````dRE = expander(thresholdValue,ratioValue)` sets the Ratio property to `ratioValue`.```
````dRE = expander(___,Name,Value)` sets each property `Name` to the specified `Value`. Unspecified properties have default values.Example: `dRE = expander('AttackTime',0.01,'SampleRate',16000)` creates a System object, `dRE`, with a 0.01 second attack time and a 16 kHz sample rate.```

## Properties

expand all

Unless otherwise indicated, properties are nontunable, which means you cannot change their values after calling the object. Objects lock when you call them, and the `release` function unlocks them.

If a property is tunable, you can change its value at any time.

Operation threshold in dB, specified as a real scalar.

Operation threshold is the level below which gain is applied to the input signal.

Tunable: Yes

Data Types: `single` | `double`

Expansion ratio, specified as a real scalar greater than or equal to 1.

Expansion ratio is the input/output ratio for signals that undershoot the operation threshold.

Assuming a hard knee characteristic and a steady-state input such that x[n] dB < `thresholdValue`, the expansion ratio is defined as $R=\frac{\left(y\left[n\right]-T\right)}{\left(x\left[n\right]-T\right)}$ .

• R is the expansion ratio.

• y[n] is the output signal in dB.

• x[n] is the input signal in dB.

• T is the threshold in dB.

Tunable: Yes

Data Types: `single` | `double`

Knee width in dB, specified as a real scalar greater than or equal to 0.

Knee width is the transition area in the expansion characteristic.

For soft knee characteristics, the transition area is defined by the relation

`$y=x+\frac{\left(1-R\right)×{\left(x-T-\frac{W}{2}\right)}^{2}}{\left(2×W\right)}$`

for the range $\left(2×|x-T|\right)\le W$.

• y is the output level in dB.

• x is the input level in dB.

• R is the expansion ratio.

• T is the threshold in dB.

• W is the knee width in dB.

Tunable: Yes

Data Types: `single` | `double`

Attack time in seconds, specified as a real scalar greater than or equal to 0.

Attack time is the time it takes the expander gain to rise from 10% to 90% of its final value when the input goes below the threshold.

Tunable: Yes

Data Types: `single` | `double`

Release time in seconds, specified as a real scalar greater than or equal to 0.

Release time is the time it takes the expander gain to drop from 90% to 10% of its final value when the input goes above the threshold.

Tunable: Yes

Data Types: `single` | `double`

Hold time in seconds, specified as a real scalar greater than or equal to 0.

Hold time is the period in which the applied gain is held constant before it starts moving toward its steady-state value. Hold time begins when the input level crosses the operation threshold.

Tunable: Yes

Data Types: `single` | `double`

Input sample rate in Hz, specified as a positive scalar.

Tunable: Yes

Data Types: `single` | `double`

## Usage

### Syntax

``audioOut = dRE(audioIn)``
``[audioOut,gain] = dRE(audioIn)``

### Description

example

````audioOut = dRE(audioIn)` performs dynamic range expansion on the input signal, `audioIn`, and returns the expanded signal, `audioOut`. The type of dynamic range expansion is specified by the algorithm and properties of the `expander` System object, `dRE`.```
````[audioOut,gain] = dRE(audioIn)` also returns the applied gain, in dB, at each input sample.```

### Input Arguments

expand all

Audio input to the expander, specified as a matrix. The columns of the matrix are treated as independent audio channels.

Data Types: `single` | `double`

### Output Arguments

expand all

Audio output from the expander, returned as a matrix the same size as `audioIn`.

Data Types: `single` | `double`

Gain applied by expander, returned as a matrix the same size as `audioIn`.

Data Types: `single` | `double`

## Object Functions

To use an object function, specify the System object as the first input argument. For example, to release system resources of a System object named `obj`, use this syntax:

`release(obj)`

expand all

 `visualize` Visualize static characteristic of dynamic range controller `createAudioPluginClass` Create audio plugin class that implements functionality of System object `parameterTuner` Tune object parameters while streaming
 `configureMIDI` Configure MIDI connections between audio object and MIDI controller `disconnectMIDI` Disconnect MIDI controls from audio object `getMIDIConnections` Get MIDI connections of audio object
 `clone` Create duplicate System object `isLocked` Determine if System object is in use `release` Release resources and allow changes to System object property values and input characteristics `reset` Reset internal states of System object `step` Run System object algorithm

The `createAudioPluginClass` and `configureMIDI` functions map tunable properties of the `expander` System object to user-facing parameters:

PropertyRangeMappingUnit
`Threshold`[–140, 0]lineardB
`Ratio`[1, 50]linearnone
`KneeWidth`[0, 20]lineardB
`AttackTime`[0, 4]linearseconds
`ReleaseTime`[0, 4]linearseconds
`HoldTime`[0, 4]linearseconds

## Examples

expand all

Use dynamic range expansion to attenuate background noise from an audio signal.

Set up the `dsp.AudioFileReader` and `audioDeviceWriter` System objects.

```frameLength = 1024; fileReader = dsp.AudioFileReader( ... 'Filename','Counting-16-44p1-mono-15secs.wav', ... 'SamplesPerFrame',frameLength); deviceWriter = audioDeviceWriter( ... 'SampleRate',fileReader.SampleRate);```

Corrupt the audio signal with Gaussian noise. Play the audio.

```while ~isDone(fileReader) x = fileReader(); xCorrupted = x + (1e-2/4)*randn(frameLength,1); deviceWriter(xCorrupted); end release(fileReader)```

Set up the expander with a threshold of -40 dB, a ratio of 10, an attack time of 0.01 seconds, a release time of 0.02 seconds, and a hold time of 0 seconds. Use the sample rate of your audio file reader.

```dRE = expander(-40,10, ... 'AttackTime',0.01, ... 'ReleaseTime',0.02, ... 'HoldTime',0, ... 'SampleRate',fileReader.SampleRate);```

Set up the scope to visualize the signal before and after dynamic range expansion.

```scope = dsp.TimeScope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpanOverrunAction','Scroll', ... 'TimeSpan',16, ... 'BufferLength',1.5e6, ... 'YLimits',[-1 1], ... 'ShowGrid',true, ... 'ShowLegend',true, ... 'Title','Corrupted vs. Expanded Audio');```

Play the processed audio and visualize it on the scope.

```while ~isDone(fileReader) x = fileReader(); xCorrupted = x + (1e-2/4)*randn(frameLength,1); y = dRE(xCorrupted); deviceWriter(y); scope([xCorrupted,y]) end release(fileReader) release(dRE) release(deviceWriter) release(scope)```

De-essing is the process of diminishing sibilant sounds in an audio signal. Sibilance refers to the s, z, and sh sounds in speech, which can be disproportionately emphasized during recording. es sounds fall under the category of unvoiced speech with all consonants and have a higher frequency than voiced speech. In this example, you apply split-band de-essing to a speech signal by separating the signal into high and low frequencies, applying an expander to diminish the sibilant frequencies, and then remixing the channels.

Create a `dsp.AudioFileReader` object and an `audioDeviceWriter` object to read from a sound file and write to an audio device. Listen to the unprocessed signal. Then release the file reader and device writer.

```fileReader = dsp.AudioFileReader( ... fullfile(matlabroot,'examples','audio','Sibilance.wav')); deviceWriter = audioDeviceWriter; while ~isDone(fileReader) audioIn = fileReader(); deviceWriter(audioIn); end release(deviceWriter) release(fileReader)```

Create an `expander` System object to de-ess the audio signal. Set the sample rate of the expander to the sample rate of the audio file. Create a two-band crossover filter with a crossover of 3000 Hz. Sibilance is usually found in this range. Set the crossover slope to 12. Plot the frequency response of the crossover filter to confirm your design visually.

```dRExpander = expander( ... 'Threshold',-50, ... 'AttackTime', 0.05, ... 'ReleaseTime',0.05, ... 'HoldTime',0.005, ... 'SampleRate',fileReader.SampleRate); crossFilt = crossoverFilter( ... 'NumCrossovers',1, ... 'CrossoverFrequencies',3000, ... 'CrossoverSlopes',12); visualize(crossFilt)```

Create a `dsp.TimeScope` System object to visualize the original and processed audio signals.

```scope = dsp.TimeScope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpanOverrunAction','Scroll', ... 'TimeSpan',4, ... 'BufferLength',fileReader.SampleRate*8, ... 'YLimits',[-1,1], ... 'ShowGrid',true, ... 'ShowLegend',true, ... 'ChannelNames',{'Original','Processed'});```

In an audio stream loop:

1. Read in a frame of the audio file.

2. Split the audio signal into two bands.

3. Apply dynamic range expansion to the upper band.

4. Remix the channels.

5. Write the processed audio signal to your audio device for listening.

6. Visualize the processed and unprocessed signals on a time scope.

As a best practice, release your objects once done.

```while ~isDone(fileReader) audioIn = fileReader(); [band1,band2] = crossFilt(audioIn); band2processed = dRExpander(band2); procAudio = band1 + band2processed; deviceWriter(procAudio); scope([audioIn procAudio]); end release(deviceWriter) release(fileReader) release(scope)```

```release(crossFilt) release(dRExpander)```

Create a `dsp.AudioFileReader` to read in audio frame-by-frame. Create a `audioDeviceWriter` to write audio to your sound card. Create a `expander` to process the audio data. Call `visualize` to plot the static characteristic of the `expander`.

```frameLength = 1024; fileReader = dsp.AudioFileReader('Counting-16-44p1-mono-15secs.wav', ... 'SamplesPerFrame',frameLength); deviceWriter = audioDeviceWriter('SampleRate',fileReader.SampleRate); dRE = expander(-40,10, ... 'AttackTime',0.01, ... 'ReleaseTime',0.02, ... 'HoldTime',0, ... 'SampleRate',fileReader.SampleRate); visualize(dRE)```

Create a `dsp.TimeScope` to visualize the original and processed audio.

```scope = dsp.TimeScope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpan',1, ... 'BufferLength',fileReader.SampleRate*4, ... 'YLimits',[-1,1], ... 'TimeSpanOverrunAction','Scroll', ... 'ShowGrid',true, ... 'LayoutDimensions',[2,1], ... 'NumInputPorts',2, ... 'Title','Original vs. Processed Audio (top) and Applied Gain in dB (bottom)'); scope.ActiveDisplay = 2; scope.YLimits = [-300,0]; scope.YLabel = 'Gain (dB)';```

Call `parameterTuner` to open a UI to tune parameters of the expander while streaming.

`parameterTuner(dRE)`

In an audio stream loop:

1. Read in a frame of audio from the file.

2. Apply dynamic range expansion.

3. Write the frame of audio to your audio device for listening.

4. Visualize the original and processed audio, and the gain applied.

While streaming, tune parameters of the dynamic range expander and listen to the effect.

```while ~isDone(fileReader) audioIn = fileReader(); [audioOut,g] = dRE(audioIn); deviceWriter(audioOut); scope([audioIn(:,1),audioOut(:,1)],g(:,1)); drawnow limitrate % required to update parameter end```

As a best practice, release your objects once done.

```release(deviceWriter) release(fileReader) release(dRE) release(scope)```

## Algorithms

expand all

The `expander` System object processes a signal frame by frame and element by element.

## References

[1] Giannoulis, Dimitrios, Michael Massberg, and Joshua D. Reiss. "Digital Dynamic Range Compressor Design –– A Tutorial and Analysis." Journal of Audio Engineering Society. Vol. 60, Issue 6, 2012, pp. 399–408.