%% Measure Frequency Response of an Audio Device
% The frequency response (FR) is an important tool for characterizing the fidelity of an audio device or component.
% This example requires an audio device capable of recording and playing audio and an appropriate audio driver. To learn more about how the example records and plays audio data, see audioDeviceReader and audioDeviceWriter.
%% Description of FR Measurement Techniques
% An FR measurement compares the output levels of an audio device to known input levels. A basic FR measurement consists of two or three test tones: mid, high, and low.
% In this example you perform an audible range FR measurement by sweeping a sine wave from the lowest frequency in the range to the highest. A flat response indicates an audio device that responds equally to all frequencies.
%% Setup Experiment
% In this example, you measure the FR by playing an audio signal through audioDeviceWriter and then recording the signal through audioDeviceReader. A loopback cable is used to physically connect the audio-out port of the sound card to its audio-in port.
%
%% Audio Device Reader and Writer
% To start, use the audioDeviceReader System object™ and audioDeviceWriter System object to connect to the audio device. This example uses a Steinberg UR44 audio device with a 48 kHz sampling rate and a buffer size of 1024 samples.

sampleRate = 48e3;
device = 'Yamaha Steinberg USB ASIO';

aDR = audioDeviceReader( ...
      'SampleRate',sampleRate, ...
      'Device',device, ...
      'Driver','ASIO', ...
      'BitDepth','16-bit integer', ...
      'ChannelMappingSource','Property', ...
      'ChannelMapping',1);

aDW = audioDeviceWriter( ...
      'SampleRate',sampleRate, ...
      'Device',device, ...
      'Driver','ASIO', ...
      'BitDepth','16-bit integer', ...
      'ChannelMappingSource','Property', ...
      'ChannelMapping',1);

%
%% Test Signal
% The test signal is a sine wave with 1024 samples per frame and an initial frequency of 0 Hz. The frequency is increased in 50 Hz increments to sweep the audible range.

samplesPerFrame = 1024;
sineSource  = audioOscillator( ...
      'Frequency',0, ...
      'SignalType','sine', ...
      'SampleRate',sampleRate, ...
      'SamplesPerFrame',samplesPerFrame);

%
%% Spectrum Analyzer
% Use the dsp.SpectrumAnalyzer to visualize the FR of your audio I/O system. 20 averages of the spectrum estimate are used throughout the experiment and the resolution bandwidth is set to 50 Hz. The sampling frequency is set to 48 kHz.

RBW = 50;
Navg = 20;

scope = dsp.SpectrumAnalyzer( ...
      'Method','Filter bank', ...
      'SampleRate',sampleRate, ...
      'RBWSource','Property','RBW',RBW, ...
      'SpectralAverages',Navg, ...
      'FrequencySpan','Start and stop frequencies',...
      'StartFrequency',0, ...
      'StopFrequency',sampleRate/2, ...
      'ReducePlotRate',false, ...
      'PlotAsTwoSidedSpectrum',false, ...
      'FrequencyScale','Log', ...
      'PlotMaxHoldTrace',true, ...
      'ShowLegend',true, ...
      'YLimits',[-110 20],...
      'YLabel','Power', ...
      'Title','Audio Device Frequency Response');

%
%% Frequency Response Measurement Loop
% To avoid the impact of setup time on the FR measurement, prerun your audio loop for 5 seconds.
% Once the actual FR measurement starts, sweep the test signal through the audible frequency range. Use the spectrum analyzer to visualize the FR.

tic
while toc < 5
    x = sineSource();
    aDW(x);
    y = aDR();
    scope(y);    
end
        
count = 1;
readerDrops = 0;
writerDrops = 0;

while true
    if count == Navg
        newFreq = sineSource.Frequency + RBW;
        if newFreq > sampleRate/2
            break
        end
        sineSource.Frequency = newFreq;
        count = 1;
    end
    x = sineSource();
    writerUnderruns = aDW(x);
    [y,readerOverruns] = aDR();
    readerDrops = readerDrops + readerOverruns;        
    writerDrops = writerDrops + writerUnderruns; 
    scope(y);        
    count = count + 1;
end

release(aDR)
release(aDW)
release(scope)

%
%% Frequency Response Measurement Results
% The spectrum analyzer shows two plots. The first plot is the spectrum estimate of the last recorded data. The second plot is the maximum power the spectrum analyzer computed for each frequency bin, as the sine wave swept over the spectrum. To get the maximum hold plot data and the frequency vector, you can use the object function getSpectrumData and plot the maximum hold trace only.

data = getSpectrumData(scope);
freqVector = data.FrequencyVector{1};
freqResponse = data.MaxHoldTrace{1};

semilogx(freqVector,freqResponse);
xlabel('Frequency (Hz)');
ylabel('Power (dBm)');
title('Audio Device Frequency Response');

%
% The frequency response plot indicates that the audio device tested in this example has a flat frequency response in the audible range.
% Copyright 2017-2018 The MathWorks, Inc.