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:
Create the
expander
object and set its properties.Call the object with arguments, as if it were a function.
To learn more about how System objects work, see What Are System Objects?
Creation
Syntax
Description
dRE = expander
creates a System object, dRE
, that performs dynamic range expansion independently
across each input channel.
dRE = expander(
sets the
Threshold
property to thresholdValue
)thresholdValue
.
dRE = expander(
sets the Ratio property
to thresholdValue
,ratioValue
)ratioValue
.
dRE = expander(___,
sets each property Name,Value
)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
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.
For more information on changing property values, see System Design in MATLAB Using System Objects.
Threshold
— Operation threshold (dB)
–10
(default) | real scalar
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
Ratio
— Expansion ratio
5
(default) | real scalar
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 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
KneeWidth
— Knee width (dB)
0
(default) | real scalar
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
for the range .
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
AttackTime
— Attack time (s)
0.05
(default) | real scalar
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
ReleaseTime
— Release time (s)
0.2
(default) | real scalar
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
HoldTime
— Hold time (s)
0.05
(default) | real scalar
Hold time in seconds, specified as a real scalar greater than or equal to 0.
Hold time is the period for which the (negative) gain is held before starting to decrease towards its steady state value when the input level drops below the threshold.
Tunable: Yes
Data Types: single
| double
SampleRate
— Input sample rate (Hz)
44100
(default) | positive scalar
Input sample rate in Hz, specified as a positive scalar.
Tunable: Yes
Data Types: single
| double
EnableSidechain
— Enable sidechain input
false
(default) | true
Enable sidechain input, specified as true
or
false
. This property determines the number of available inputs on
the expander
object.
The sidechain datatype and (frame) length must be the same as audioIn
.
The number of channels of the sidechain must be equal to the number of channels of
audioIn
or
be equal to one. When the number of sidechain channels is one, the gain
computed based on this channel is applied to all channels of audioIn
.
When the number of sidechain channels is equal to the number of channels in audioIn
, the
gain
computed for each sidechain channel is applied to the corresponding channel of audioIn
.
Tunable: No
Usage
Description
Input Arguments
audioIn
— Audio input to expander
matrix
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
audioOut
— Audio output from expander
matrix
Audio output from the expander, returned as a matrix the same size as
audioIn
.
Data Types: single
| double
gain
— Gain applied by expander (dB)
matrix
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)
Specific to expander
visualize | Visualize static characteristic of dynamic range controller |
staticCharacteristic | Return static characteristic of dynamic range controller |
createAudioPluginClass | Create audio plugin class that implements functionality of System object |
parameterTuner | Tune object parameters while streaming |
MIDI
configureMIDI | Configure MIDI connections between audio object and MIDI controller |
disconnectMIDI | Disconnect MIDI controls from audio object |
getMIDIConnections | Get MIDI connections of audio object |
The createAudioPluginClass
and configureMIDI
functions map tunable properties of the expander
System object to user-facing parameters:
Property | Range | Mapping | Unit |
---|---|---|---|
Threshold | [–140, 0] | linear | dB |
Ratio | [1, 50] | linear | none |
KneeWidth | [0, 20] | linear | dB |
AttackTime | [0, 4] | linear | seconds |
ReleaseTime | [0, 4] | linear | seconds |
HoldTime | [0, 4] | linear | seconds |
Examples
Expand Audio Signal
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 = timescope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpanOverrunAction','Scroll', ... 'TimeSpanSource','property','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)
Apply Split-Band De-Essing
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( ... '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 timescope
object to visualize the original and processed audio signals.
scope = timescope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpanOverrunAction','Scroll', ... 'TimeSpanSource','Property','TimeSpan',4, ... 'BufferLength',fileReader.SampleRate*8, ... 'YLimits',[-1 1], ... 'ShowGrid',true, ... 'ShowLegend',true, ... 'ChannelNames',{'Original','Processed'});
In an audio stream loop:
Read in a frame of the audio file.
Split the audio signal into two bands.
Apply dynamic range expansion to the upper band.
Remix the channels.
Write the processed audio signal to your audio device for listening.
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)
Tune Expander Parameters
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 timescope
to visualize the original and processed audio.
scope = timescope( ... 'SampleRate',fileReader.SampleRate, ... 'TimeSpanSource','property','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:
Read in a frame of audio from the file.
Apply dynamic range expansion.
Write the frame of audio to your audio device for listening.
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 when done.
release(deviceWriter) release(fileReader) release(dRE) release(scope)
Sidechain Dynamic Range Expansion
Use the EnableSidechain input of an expander
object to emulate an electronic drum controller, also known as a multipad. This technique is common in recording studio production and creates interesting changes to the timbre of an instrument. The sidechain signal controls the expansion on the input signal. Sidechain expansion decreases the amplitude of the input signal when the sidechain signal falls below the Threshold of the expander
.
Prepare Audio Files
Convert the sidechain signal from stereo to mono.
[expanderSideChainStereo,Fs] = audioread('FunkyDrums-44p1-stereo-25secs.mp3');
expanderSideChainMono = (expanderSideChainStereo(:,1) + expanderSideChainStereo(:,2)) / 2;
Write the converted sidechain signal to a file.
audiowrite('convertedSidechainSig.wav',expanderSideChainMono,Fs);
Construct Audio Objects
Construct a dsp.AudioFileReader
object for the input and sidechain signals. To allow the script to run indefinitely, change the playbackCount
variable from 1
to Inf
.
inputAudio = 'SoftGuitar-44p1_mono-10mins.ogg'; sidechainAudio = 'convertedSidechainSig.wav'; playbackCount = 1; inputAudioAFR = dsp.AudioFileReader(inputAudio,'PlayCount',playbackCount); sidechainAudioAFR = dsp.AudioFileReader(sidechainAudio,'PlayCount',playbackCount);
Construct and visualize an expander
object. Use a high Ratio, a soft KneeWidth, a fast AttackTime and ReleaseTime, and a short HoldTime.
dRE = expander('EnableSidechain',true,'Threshold',-20,'Ratio',6.5,... 'KneeWidth',20,'AttackTime',0.84,'ReleaseTime',0.001,'HoldTime',0.0001); visualize(dRE)
Construct an audioDeviceWriter
object to play the sidechain and input signals.
afw = audioDeviceWriter;
Construct a timescope
object to view the input signal, the sidechain signal, as well as the expanded input signal.
scope = timescope('NumInputPorts',3,... 'SampleRate',Fs,... 'TimeSpanSource','property',... 'TimeSpan',5,... 'TimeDisplayOffset',0,... 'LayoutDimensions',[3 1],... 'BufferLength',Fs*15,... 'TimeSpanOverrunAction','Scroll',... 'YLimits',[-1 1],... 'ShowGrid',true,... 'Title','Input Audio - Classical Guitar'); scope.ActiveDisplay = 2; scope.YLimits = [-1 1]; scope.Title = 'Sidechain Audio - Drums'; scope.ShowGrid = true; scope.ActiveDisplay = 3; scope.YLimits = [-1 1]; scope.ShowGrid = true; scope.Title = 'Expanded Input Audio - Classical Guitar';
Call parameterTuner
to open a UI to tune parameters of the expander while streaming. Adjust the property values and listen to the effect in real time.
parameterTuner(dRE)
Create Audio Streaming Loop
Read in a frame of audio from your input and sidechain signals. Process your input and sidechain signals with your expander
object. Playback your processed audio signals and display the audio data using a timescope
object.
The top panel of your timescope
displays the input audio signal and the middle panel displays the sidechain audio signal. The bottom panel displays the expanded input audio signal.
Substitute different audio files for your inputAudio
variable to create different textures and timbres in your drum mix.
while ~isDone(sidechainAudioAFR) inputAudioFrame = inputAudioAFR(); sideChainAudioFrame = sidechainAudioAFR(); expanderOutput = dRE(inputAudioFrame,sideChainAudioFrame); afw(sideChainAudioFrame+expanderOutput); scope(inputAudioFrame,sideChainAudioFrame,expanderOutput); drawnow limitrate; % required to update parameter settings from UI end
Release your objects.
release(inputAudioAFR) release(sidechainAudioAFR) release(dRE) release(afw) release(scope)
Algorithms
The expander
System object processes a signal frame by frame and element by element.
Convert Input Signal to dB
The N-point signal, x[n], is converted to decibels:
Gain Computer
xdB[n] passes through the gain computer. The gain computer uses the static characteristic properties of the dynamic range expander to attenuate gain that is below the threshold.
If you specified a soft knee, the gain computer has the following static characteristic:
where T is the threshold, R is the ratio, and W is the knee width.
If you specified a hard knee, the gain computer has the following static characteristic:
The computed gain, gc[n], is calculated as
Gain Smoothing
gc[n] is smoothed using specified attack, release, and hold time properties:
The attack time coefficient, αA , is calculated as
The release time coefficient, αR , is calculated as
TA
is the attack time period, specified by the
AttackTime
property. TR
is the release time period, specified by the
ReleaseTime
property. Fs is the input sampling rate, specified by the
SampleRate
property.
CA is the hold counter for attack. The limit, TH
, is determined by the HoldTime
property.
Calculate and Apply Linear Gain
The smoothed gain in dB, gs[n], is translated to a linear domain:
The output of the dynamic range expander is given as
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.
Extended Capabilities
C/C++ Code Generation
Generate C and C++ code using MATLAB® Coder™.
Usage notes and limitations:
System Objects in MATLAB Code Generation (MATLAB Coder)
Version History
Introduced in R2016a
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list:
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)