Main Content

crossoverFilter

Audio crossover filter

Description

The crossoverFilter System object™ implements an audio crossover filter, which is used to split an audio signal into two or more frequency bands. Crossover filters are multiband filters whose overall magnitude frequency response is flat.

To implement an audio crossover filter:

  1. Create the crossoverFilter object and set its properties.

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

Description

crossFilt = crossoverFilter creates a System object, crossFilt, that implements an audio crossover filter.

crossFilt = crossoverFilter(nCrossovers) sets the NumCrossovers property to nCrossovers.

crossFilt = crossoverFilter(nCrossovers,xFrequencies) sets the CrossoverFrequencies property to xFrequencies.

crossFilt = crossoverFilter(nCrossovers,xFrequencies,xSlopes) sets the CrossoverSlopes property to xSlopes.

crossFilt = crossoverFilter(nCrossovers,xFrequencies,xSlopes,Fs) sets the SampleRate property to Fs.

crossFilt = crossoverFilter(___,Name,Value) sets each property Name to the specified Value. Unspecified properties have default values.

Example: crossFilt = crossoverFilter(2,'CrossoverFrequencies',[100,800],'CrossoverSlopes',[6,48]) creates a System object, crossFilt, with two crossovers located at 100 Hz and 800 Hz, and crossover slopes of 6 dB/octave and 48 dB/octave, respectively.

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.

For more information on changing property values, see System Design in MATLAB Using System Objects.

Number of magnitude response band crossings, specified as a scalar integer in the range 1 to 4.

The number of bands output when implementing crossover filtering is one more than the NumCrossovers value.

Number of magnitude response band crossingsNumber of bands output
1two-band
2three-band
3four-band
4five-band

Tunable: No

Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Crossover frequencies in Hz, specified as a scalar or vector of real values of length NumCrossovers.

Crossover frequencies are the intersections of magnitude response bands of the individual two-band crossover filters used in the multiband crossover filter.

Tunable: Yes

Data Types: single | double

Crossover slopes in dB/octave, specified as a scalar or vector of real values in the range [6:6:48]. If a specified crossover slope is not inside the range, the slope is rounded to the nearest allowed value.

  • If CrossoverSlopes is a scalar, all two-band component crossover slopes take that value.

  • If CrossoverSlopes is a vector of length NumCrossovers, the respective two-band component crossover slopes take those values.

Crossover slopes are the slopes of individual bands at the associated crossover frequency, as specified in the two-band component crossover.

Tunable: Yes

Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

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

Tunable: Yes

Data Types: single | double

Usage

Description

example

[band1,...,bandN] = crossFilt(audioIn) applies a crossover filter on the input, audioIn, and returns the filtered output bands, [band1,...,bandN], where N = NumCrossovers + 1.

Input Arguments

expand all

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

Data Types: single | double

Output Arguments

expand all

Audio bands output from the crossover filter, returned as a set of N bands. The NumCrossovers property determines the number of return arguments: N = NumCrossovers + 1. The size of each output argument is 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

visualizeVisualize magnitude response of crossover filter
costEstimate implementation cost of audio System objects
createAudioPluginClassCreate audio plugin class that implements functionality of System object
parameterTunerTune object parameters while streaming
configureMIDIConfigure MIDI connections between audio object and MIDI controller
disconnectMIDIDisconnect MIDI controls from audio object
getMIDIConnectionsGet MIDI connections of audio object
cloneCreate duplicate System object
isLockedDetermine if System object is in use
releaseRelease resources and allow changes to System object property values and input characteristics
resetReset internal states of System object
stepRun System object algorithm

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

PropertyRangeMappingUnit
CrossoverFrequencies[20, 20000]linearHz
CrossoverSlopes[6, 48]lineardB/octave

Examples

collapse all

Use the crossoverFilter object to split Gaussian noise into three separate frequency bands.

Create a 5 second noise signal that assumes a 24 kHz sample rate.

fs = 24e3;
noise = randn(fs*5,1);

Create a crossoverFilter object with 2 crossovers (3 bands), crossover frequencies at 4 kHz and 8 kHz, a slope of 48 dB/octave, and a sample rate of 24 kHz.

crossFilt = crossoverFilter( ...
    NumCrossovers=2, ...
    CrossoverFrequencies=[4000,8000], ...
    CrossoverSlopes=48, ...
    SampleRate=fs);

Visualize the magnitude response of your crossover filter object.

visualize(crossFilt)

Call your crossover filter like a function with the noise signal as the argument.

[y1,y2,y3] = crossFilt(noise);

Visualize the results using a spectrogram.

tiledlayout(4,1)

nexttile
stft(noise,fs,FrequencyRange="onesided")
title("Noise")

nexttile
stft(y1,fs,FrequencyRange="onesided")
title("y1")

nexttile
stft(y2,fs,FrequencyRange="onesided")
title("y2")

nexttile
stft(y3,fs,FrequencyRange="onesided")
title("y3")

Use the crossoverFilter object to split an audio signal into three frequency bands.

Create the dsp.AudioFileReader and audioDeviceWriter objects. Use the sample rate of the reader as the sample rate of the writer.

samplesPerFrame = 256;

fileReader = dsp.AudioFileReader( ...
    "RockGuitar-16-44p1-stereo-72secs.wav", ...
    SamplesPerFrame=samplesPerFrame);
deviceWriter = audioDeviceWriter( ...
    SampleRate=fileReader.SampleRate);

Create a crossoverFilter object with 2 crossovers (3 bands), crossover frequencies at 500 Hz and 1 kHz, and a slope of 18 dB/octave. Use the sample rate of the reader as the sample rate of the crossover filter.

crossFilt = crossoverFilter( ...
    NumCrossovers=2, ...
    CrossoverFrequencies=[500,1000], ...
    CrossoverSlopes=18, ...
    SampleRate=fileReader.SampleRate);

Visualize the bands of the crossover filter.

visualize(crossFilt)

Get the cost of the crossover filter.

cost(crossFilt)
ans = struct with fields:
                  NumCoefficients: 48
                        NumStates: 18
    MultiplicationsPerInputSample: 48
          AdditionsPerInputSample: 37

Create a spectrum analyzer to visualize the effect of the crossover filter.

scope = spectrumAnalyzer( ...
    SampleRate=fileReader.SampleRate, ...
    PlotAsTwoSidedSpectrum=false, ...
    FrequencyScale="log", ...
    Title="Crossover Bands and Reconstructed Signal", ...
    ShowLegend=true, ...
    ChannelNames=["Original Signal","Band 1","Band 2","Band 3","Sum"]);

Play 10 seconds of the audio signal. Visualize the spectrum of the original audio, the crossover bands, and the reconstructed signal (sum of bands).

setup(scope,ones(samplesPerFrame,5))
count = 0;
while count < (fileReader.SampleRate/samplesPerFrame)*10
    originalSignal = fileReader();
    [band1,band2,band3] = crossFilt(originalSignal);
    sumOfBands = band1 + band2 + band3;
    scope([originalSignal(:,1), ...
           band1(:,1), ...
           band2(:,1), ...
           band3(:,1), ...
           sumOfBands(:,1)])
    deviceWriter(sumOfBands);
    count = count + 1;
end

release(fileReader)
release(crossFilt)
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( ...
    '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:

  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)

Plosives are consonant sounds resulting from a sudden release of airflow. They are most pronounced in words beginning with p, d, and g sounds. Plosives can be emphasized by the recording process and are often displeasurable to hear. In this example, you minimize the plosives of a speech signal by applying highpass filtering and low-band compression.

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

fileReader = dsp.AudioFileReader('audioPlosives.wav');
deviceWriter = audioDeviceWriter('SampleRate',fileReader.SampleRate);

while ~isDone(fileReader)
    audioIn = fileReader();
    deviceWriter(audioIn);
end
release(deviceWriter)
release(fileReader)

Design a highpass filter with a steep rolloff of all frequencies below 120 Hz. Use a dsp.SOSFilter object to implement the highpass filter design. Create a crossover filter with one crossover at 250 Hz. The crossover filter enables you to separate the band of interest for processing. Create a dynamic range compressor to compress the dynamic range of plosive sounds. To apply no make-up gain, set the MakeUpGainMode to "Property" and use the default 0 dB MakeUpGain property value. Create a time scope to visualize the processed and unprocessed audio signal.

[B,A] = designVarSlopeFilter(48,120/(fileReader.SampleRate/2),"hi",Orientation="row");
biquadFilter = dsp.SOSFilter(B,A);

crossFilt = crossoverFilter( ...
    "SampleRate",fileReader.SampleRate, ...
    "NumCrossovers",1, ...
    "CrossoverFrequencies",250, ...
    "CrossoverSlopes",48);

dRCompressor = compressor( ...
    "Threshold",-35, ...
    "Ratio",10, ...
    "KneeWidth",20, ...
    "AttackTime",1e-4, ...
    "ReleaseTime",3e-1, ...
    "MakeUpGainMode","Property", ...
    "SampleRate",fileReader.SampleRate);

scope = timescope( ...
    "SampleRate",fileReader.SampleRate, ...
    "TimeSpanSource","property","TimeSpan",3, ...
    "BufferLength",fileReader.SampleRate*3*2, ...
    "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. Apply highpass filtering using your biquad filter.

  3. Split the audio signal into two bands.

  4. Apply dynamic range compression to the lower band.

  5. Remix the channels.

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

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

As a best practice, release your objects once done.

while ~isDone(fileReader)
    audioIn = fileReader();
    audioIn = biquadFilter(audioIn);
    [band1,band2] = crossFilt(audioIn);
    band1compressed = dRCompressor(band1);
    audioOut = band1compressed + band2;
    deviceWriter(audioOut);
    scope([audioIn audioOut])
end

As a best practice, release your objects once done.

release(deviceWriter)
release(fileReader)
release(crossFilt)
release(dRCompressor)
release(scope)

Create a dsp.AudioFileReader to read in audio frame-by-frame. Create a audioDeviceWriter to write audio to your sound card. Create a crossoverFilter to process the audio data. Call visualize to plot the frequency responses of the filters.

frameLength = 1024;
fileReader = dsp.AudioFileReader('RockDrums-44p1-stereo-11secs.mp3', ...
    'SamplesPerFrame',frameLength);
deviceWriter = audioDeviceWriter('SampleRate',fileReader.SampleRate);

xFilt = crossoverFilter('SampleRate',fileReader.SampleRate);
visualize(xFilt)

Call parameterTuner to open a UI to tune parameters of the crossover filter while streaming.

parameterTuner(xFilt)

In an audio stream loop:

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

  2. Apply crossover filtering.

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

While streaming, tune parameters of the crossover filter and listen to the effect.

while ~isDone(fileReader)
    audioIn = fileReader();
    [low,high] = xFilt(audioIn);
    deviceWriter([low(:,1),high(:,1)]);
    drawnow limitrate % required to update parameter
end

As a best practice, release your objects once done.

release(deviceWriter)
release(fileReader)
release(xFilt)

Algorithms

expand all

The crossover System object is implemented as a binary tree of crossover pairs with additional phase-compensating sections [1]. Odd-order crossovers are implemented with Butterworth filters, while even-order crossovers are implemented with cascaded Butterworth filters (Linkwitz-Riley filters).

References

[1] D’Appolito, Joseph A. "Active Realization of Multiway All-Pass Crossover Systems." Journal of Audio Engineering Society. Vol. 35, Issue 4, 1987, pp. 239–245.

Extended Capabilities

Version History

Introduced in R2016a