Main Content


Read SOFA files

Since R2023b



    s = sofaread(filename) reads in data from the SOFA file specified by filename into the object s.


    collapse all

    Use sofaread to read in a SOFA file. The file follows the SimpleFreeFieldHRIR convention, which stores head-related transfer function (HRTF) measurement data in FIR filter form.

    filename = "ReferenceHRTF.sofa";
    s = sofaread(filename)
    s = 
      audio.sofa.SimpleFreeFieldHRIR handle with properties:
                Numerator: [1550x2x256 double]
                    Delay: [0 0]
             SamplingRate: 48000
        SamplingRateUnits: "hertz"
      Show all properties

    Select the impulse response data corresponding to the fifth measurement for the left ear.

    measurementIdx = 5;
    ear = 1;
    ir = squeeze(s.Numerator(measurementIdx,ear,:));

    Plot the impulse response. Use the sample rate specified in the file to convert from samples to seconds.

    fs = s.SamplingRate;
    t = (0:size(ir,1)-1)/fs;
    grid on
    xlabel("Time (s)")
    ylabel("Impulse response")

    Figure contains an axes object. The axes object with xlabel Time (s), ylabel Impulse response contains an object of type line.

    Print the source position corresponding to this impulse response measurement.

    srPos = s.SourcePosition(measurementIdx,:);
    fprintf("The coordinates are %s.\n", s.SourcePositionType);
    The coordinates are spherical.
    fprintf("Units are %s.\n", s.SourcePositionUnits);
    Units are degree, degree, meter.
    fprintf("Azimuth: %f. Elevation: %f. Radius: %f.\n",...
        srPos(1), srPos(2), srPos(3));
    Azimuth: 0.000000. Elevation: -10.000000. Radius: 3.000000.

    Load a SOFA file.

    s = sofaread("ReferenceHRTF.sofa");

    Inspect the DateModified property to see when the file was last modified.

    ans = 
    "2023-04-28 13:37:09"

    Modify the Title and History properties of the SOFA object.

    s.Title = "Modified title";
    s.History = sprintf("%s\nModified title.", s.History);

    Save the modified object to a new SOFA file.


    Load a SOFA file containing HRTF measurements.

    s = sofaread("ReferenceHRTF.sofa");

    Specify the desired source positions and then calculate the HRTF at these locations using the interpolateHRTF function.

    desiredAz = [-120;-60;0;60;120;0;-120;120];
    desiredEl = [-90;90;45;0;-45;0;45;45];
    desiredPosition = [desiredAz desiredEl];
    interpolatedIR  = interpolateHRTF(s,desiredPosition);

    Create an audio file sampled at 48 kHz for compatibility with the SOFA file.

    [audio,fs] = audioread("Counting-16-44p1-mono-15secs.wav");
    audio = audioresample(audio,InputRate=fs,OutputRate=s.SamplingRate);
    audio = audio./max(abs(audio));

    Create a dsp.AudioFileReader object to read in a file frame by frame. Create an audioDeviceWriter object to play audio to your sound card frame by frame. Create a dsp.FrequencyDomainFIRFilter object. Set the Numerator property to the combined left-ear and right-ear filter pair. Since you want to keep the received signals at each ear separate, set SumFilteredOutputs to false.

    fileReader = dsp.AudioFileReader("Counting-16-48-mono-15secs.wav");
    deviceWriter = audioDeviceWriter(SampleRate=fileReader.SampleRate);
    spatialFilter = dsp.FrequencyDomainFIRFilter(squeeze(interpolatedIR(1,:,:)),SumFilteredOutputs=false);

    In an audio stream loop:

    1. Read in a frame of audio data.

    2. Feed the audio data through filter.

    3. Write the audio to your output device. If you have a stereo output hardware, such as headphones, you can hear the source shifting position over time.

    4. Modify the desired source position in 2-second intervals by updating the filter coefficients.

    durationPerPosition = 2;
    samplesPerPosition = durationPerPosition*fileReader.SampleRate;
    samplesPerPosition = samplesPerPosition - rem(samplesPerPosition,fileReader.SamplesPerFrame);
    sourcePositionIndex = 1;
    samplesRead = 0;
    while ~isDone(fileReader)
        audioIn = fileReader();
        samplesRead = samplesRead + fileReader.SamplesPerFrame;
        audioOut = spatialFilter(audioIn);
        if mod(samplesRead,samplesPerPosition) == 0
            sourcePositionIndex = sourcePositionIndex + 1;
            spatialFilter.Numerator = squeeze(interpolatedIR(sourcePositionIndex,:,:));

    As a best practice, release your System objects when complete.


    Read in a SOFA file that follows the SimpleFreeFieldHRTF convention and contains measurements in frequency response form.

    s = sofaread("freqResponseData.sofa");

    Select the complex frequency response corresponding to the tenth measurement and the right ear.

    measurementIdx = 10;
    ear = 2;
    freqResponse = squeeze(s.FrequencyResponse(measurementIdx,ear,:));

    Plot the magnitude response in decibels.

    xlabel("Frequency (Hz)")
    ylabel("Magnitude (dB)")

    Figure contains an axes object. The axes object with xlabel Frequency (Hz), ylabel Magnitude (dB) contains an object of type line.

    Read in a SOFA file that follows the SimpleFreeFieldHRSOS convention and contains mock SOS data.

    s = sofaread("mockSOSData.sofa");

    Select the numerator and denominator coefficients of the SOS filter corresponding to the first measurement and left ear.

    measurementIdx = 1;
    ear = 1;
    numerator = squeeze(s.Numerator(measurementIdx,ear,:,:));
    denominator = squeeze(s.Denominator(measurementIdx,ear,:,:));

    Use freqz to visualize the frequency response of the filter.

    sos = [numerator denominator];

    Figure contains 2 axes objects. Axes object 1 with title Phase, xlabel Normalized Frequency (\times\pi rad/sample), ylabel Phase (degrees) contains an object of type line. Axes object 2 with title Magnitude, xlabel Normalized Frequency (\times\pi rad/sample), ylabel Magnitude (dB) contains an object of type line.

    Input Arguments

    collapse all

    Name of the SOFA file to read, specified as a string scalar or character vector.

    Data Types: char | string

    Output Arguments

    collapse all

    More About

    collapse all

    SOFA Files

    Spatially oriented format for acoustics (SOFA) is a file format for storing spatially oriented acoustic data like head-related transfer functions (HRTF) and binaural or spatial room impulse responses. The AES69 standard [3] defines the SOFA file format.


    [1] Majdak, P., Zotter, F. Brinkmann, F., De Muynke, J., Mihocic, M., and Noisternig, M., “Spatially Oriented Format for Acoustics 2.1: Introduction and Recent Advances.” Journal of the Audio Engineering Society 70, no. 7/8 (July 25, 2022): 565–84.

    [2] Majdak, P., Carpentier, T., Nicol, R., Roginska, A., Suzuki, Y., Watanabe, K., Wierstorf, H., et al., “Spatially Oriented Format for Acoustics: A Data Exchange Format Representing Head-Related Transfer Functions.” In Proceedings of the 134th Convention of the Audio Engineering Society (AES), Paper 8880. Roma, Italy, 2013.

    [3] AES69-2022. "AES standard for file exchange - Spatial acoustic data file format." Standard of the Audio Engineering Society.

    Version History

    Introduced in R2023b