Logo Search packages:      
Sourcecode: octave-matcompat version File versions

auload.m

## Copyright (C) 1999 Paul Kienzle
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

## usage: [x, fs, sampleformat] = auload('filename.ext')
##
## Reads an audio waveform from a file.  Returns the audio samples in
## data, one column per channel, one row per time slice.  Also returns
## the sample rate and stored format (one of ulaw, alaw, char, short,
## long, float, double). The sample value will be normalized to the
## range [-1,1) regardless of the stored format.  This does not do any
## level correction or DC offset correction on the samples.
##
## Example
##    [x, fs] = auload(file_in_loadpath("sample.wav"));
##    auplot(x,fs);

function [data, rate, sampleformat] = auload(path)

  if (nargin != 1)
    usage("[x, fs, sampleformat] = auload('filename.ext')");
  end
  data = [];       # if error then read nothing
  rate = 8000;
  sampleformat = 'ulaw';
  ext = rindex(path, '.');
  if (ext == 0)
    usage('x = auload(filename.ext)');
  end
  ext = tolower(substr(path, ext+1, length(path)-ext));

  [file, msg] = fopen(path, 'r');
  if (file == -1)
    error([ msg, ": ", path]);
  end

  msg = sprintf('Invalid audio header: %s', path);
  ## Microsoft .wav format
  if strcmp(ext,'wav') 

    ## Header format obtained from sox/wav.c
    ## April 15, 1992
    ## Copyright 1992 Rick Richardson
    ## Copyright 1991 Lance Norskog And Sundry Contributors
    ## This source code is freely redistributable and may be used for
    ## any purpose.  This copyright notice must be maintained. 
    ## Lance Norskog And Sundry Contributors are not responsible for 
    ## the consequences of using this software.

    ## check the file magic header bytes
    arch = 'ieee-le';
    str = setstr(fread(file, 4, 'char')');
    if !strcmp(str, 'RIFF')
      error(msg);
    end
    len = fread(file, 1, 'long', 0, arch);
    str = setstr(fread(file, 4, 'char')');
    if !strcmp(str, 'WAVE')
      error(msg);
    end

    ## skip to the "fmt " section, ignoring everything else
    while (1)
      if feof(file)
            error(msg);
      end
      str = setstr(fread(file, 4, 'char')');
      len = fread(file, 1, 'long', 0, arch);
      if strcmp(str, 'fmt ')
      break;
      end
      fseek(file, len, SEEK_CUR);
    end

    ## read the "fmt " section
    formatid = fread(file, 1, 'short', 0, arch);
    channels = fread(file, 1, 'short', 0, arch);
    rate = fread(file, 1, 'long', 0, arch);
    fread(file, 1, 'long', 0, arch);
    fread(file, 1, 'short', 0, arch);
    bits = fread(file, 1, 'short', 0, arch);
    fseek(file, len-16, SEEK_CUR);

    if (formatid == 1)
      if bits == 8
            sampleformat = 'uchar';
      precision = 'uchar';
      elseif bits == 16
            sampleformat = 'short';
      precision = 'short';
      elseif bits == 32
      sampleformat = 'long';
      precision = 'long';
      else
            error(msg);
      endif
    elseif (formatid == 6 && bits == 8)
      sampleformat = 'alaw';
      precision = 'uchar';
    elseif (formatid == 7 && bits == 8)
      sampleformat = 'ulaw';
      precision = 'uchar';
    else
      error(msg);
      return;
    endif

    ## make sure the next section is a "data" section
    str = setstr(fread(file, 4, 'char')');
    if !strcmp(str, 'data')
      error(msg);
      return;
    end
    len = fread(file, 1, 'long', 0, arch);

  ## Sun .au format
  elseif strcmp(ext, 'au')

    ## Header format obtained from sox/au.c
    ## September 25, 1991
    ## Copyright 1991 Guido van Rossum And Sundry Contributors
    ## This source code is freely redistributable and may be used for
    ## any purpose.  This copyright notice must be maintained. 
    ## Guido van Rossum And Sundry Contributors are not responsible for 
    ## the consequences of using this software.

    str = setstr(fread(file, 4, 'char')');
    magic=' ds.';
    invmagic='ds. ';
    magic(1) = setstr(0);
    invmagic(1) = setstr(0);
    if strcmp(str, 'dns.') || strcmp(str, magic)
      arch = 'ieee-le';
    elseif strcmp(str, '.snd') || strcmp(str, invmagic)
      arch = 'ieee-be';
    else
      error(msg);
    end
    header = fread(file, 1, 'long', 0, 'ieee-be');
    data = fread(file, 1, 'long', 0, 'ieee-be');
    formatid = fread(file, 1, 'long', 0, 'ieee-be');
    rate = fread(file, 1, 'long', 0, 'ieee-be');
    channels = fread(file, 1, 'long', 0, 'ieee-be');
    fseek(file, header-24, SEEK_CUR); % skip file comment

    ## interpret the sample format
    if formatid == 1
      sampleformat = 'ulaw';
      precision = 'uchar';
      bits = 12;
    elseif formatid == 2
      sampleformat = 'uchar';
      precision = 'uchar';
      bits = 8;
    elseif formatid == 3
      sampleformat = 'short';
      precision = 'short';
      bits = 16;
    elseif formatid == 5
      sampleformat = 'long';
      precision = 'long';
      bits = 32;
    elseif formatid == 6
      sampleformat = 'float';
      precision = 'float';
      bits = 32;
    elseif formatid == 7
      sampleformat = 'double';
      precision = 'double';
      bits = 64;
    else
      error(msg);
    end
      
  ## Apple/SGI .aiff format
  elseif strcmp(ext,'aiff')

    ## Header format obtained from sox/aiff.c
    ## September 25, 1991
    ## Copyright 1991 Guido van Rossum And Sundry Contributors
    ## This source code is freely redistributable and may be used for
    ## any purpose.  This copyright notice must be maintained. 
    ## Guido van Rossum And Sundry Contributors are not responsible for 
    ## the consequences of using this software.
    ##
    ## IEEE 80-bit float I/O taken from
    ##        ftp://ftp.mathworks.com/pub/contrib/signal/osprey.tar
    ##        David K. Mellinger
    ##        dave@mbari.org
    ##        +1-831-775-1805
    ##        fax       -1620
    ##        Monterey Bay Aquarium Research Institute
    ##        7700 Sandholdt Road
 
    ## check the file magic header bytes
    arch = 'ieee-be';
    str = setstr(fread(file, 4, 'char')')
    if !strcmp(str, 'FORM')
      error(msg);
    end
    len = fread(file, 1, 'long', 0, arch)
    str = setstr(fread(file, 4, 'char')')
    if !strcmp(str, 'AIFF')
      error(msg);
    end

    ## skip to the "COMM" section, ignoring everything else
    while (1)
      if feof(file)
            error(msg);
      end
      str = setstr(fread(file, 4, 'char')')
      len = fread(file, 1, 'long', 0, arch)
      if strcmp(str, 'COMM')
      break;
      end
      fseek(file, len, SEEK_CUR);
    end

    ## read the "COMM" section
    channels = fread(file, 1, 'short', 0, arch)
    frames = fread(file, 1, 'long', 0, arch)
    bits = fread(file, 1, 'short', 0, arch)
    exp = fread(file, 1, 'ushort', 0, arch);    % read a 10-byte float
    mant = fread(file, 2, 'ulong', 0, arch);
    mant = mant(1) / 2^31 + mant(2) / 2^63;
    if (exp >= 32768), mant = -mant; exp = exp - 32768; end
    exp = exp - 16383;
    rate = mant * 2^exp
    fseek(file, len-18, SEEK_CUR);

    ## skip to the "SSND" section, ignoring everything else
    while (1)
      if feof(file)
            error(msg);
      end
      str = setstr(fread(file, 4, 'char')')
      len = fread(file, 1, 'long', 0, arch)
      if strcmp(str, 'SSND')
      break;
      end
      fseek(file, len, SEEK_CUR);
    end
    offset = fread(file, 1, 'long', 0, arch)
    fread(file, 1, 'long', 0, arch)
    fseek(file, offset, SEEK_CUR);

    if bits == 8
      precision = 'uchar';
      sampleformat = 'uchar';
    elseif bits == 16
      precision = 'short';
      sampleformat = 'short';
    elseif bits == 32
      precision = 'long';
      sampleformat = 'long';
    else
      error(msg);
    endif
    
  ## file extension unknown
  else
    error('auload(filename.ext) understands .wav .au and .aiff only');
  end

  ## suck in all the samples
  data = fread(file, Inf, precision, 0, arch);
  fclose(file);

  ## convert samples into range [-1, 1)
  if strcmp(sampleformat, 'alaw')
    alaw = [ \
           -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736, \
           -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784, \
           -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368, \
           -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392, \
          -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, \
          -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, \
          -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472, \
          -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, \
            -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296, \
            -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424, \
             -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40, \
            -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168, \
           -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184, \
           -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696, \
            -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592, \
            -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848 ];
    alaw = [ alaw, -alaw]/32768;
    data = alaw(data+1);
  elseif strcmp(sampleformat, 'ulaw')
    data = mu2lin(data, 16)/32768;
  elseif strcmp(sampleformat, 'uchar')
    data = data/128 - 1;
  elseif strcmp(sampleformat, 'short')
    data = data/32768;
  elseif strcmp(sampleformat, 'long')
    data = data/2^31;
  end
  data = reshape(data, channels, length(data)/channels)';

endfunction

%!demo
%! [x, fs] = auload(file_in_loadpath("sample.wav"));
%! auplot(x,fs);

Generated by  Doxygen 1.6.0   Back to index