Code covered by the BSD License  

Highlights from
Nero AAC Codec Wrapper

Nero AAC Codec Wrapper

by

 

MATLAB wrapper functions for Nero AAC Codec (v1.0)

neroaacwrite.m
function neroaacwrite(varargin)
%NEROAACWRITE Write Advanced Audio Coding sound file.
%   NEROAACWRITE is a MATLAB wrapper function for Nero AAC Encoder, which is
%   downloadable for free at http://www.nero.com/eng/technologies-aac-codec.html
%
%   NEROAACWRITE(Y,AACFILE) writes the data stored in the variable Y to a
%   AAC file called AACFILE. The AACFILE input is a string enclosed in
%   single quotes. If AACFILE does not have a file extension, NEROAACWRITE
%   appends ".m4a". The sample rate is set to the default 8000 Hz with 16
%   bits per sample. Each column of Y representsa separate channel.
%   Therefore, stereo data should be specified as a matrix with two
%   columns. The AAC encoder is configured in one-pass mode with quality
%   rating of 0.5.
%
%   NEROAACWRITE(Y,FS,AACFILE) specifies the sampling rate Fs. Supported
%   sampling rates are 8000, 11025, 16000, 22050, 32000, 44100, 48000,
%   88200, 96000, and 192000 Hz. If the specified FS is not supported,
%   NEROAACWRITE resamples Y to the nearest next sampling rate.
%
%   NEROAACWRITE(Y,FS,NBITS,AACFILE) sets the bit depth to NBITS. NBITS
%   must be 8, 16, 24, or 32.
%
%   NEROAACWRITE(Y,FS,NBITS,QMODE,QVAL,AACFILE) specifies quality/bitrate
%   setting. QMODE may be one of 'q' (quality), 'br' (bitrate), 'cbr'
%   (constant bitrate). For the 'quality' mode, QVAL must be a value
%   between 0.0 to 1.0 (larger the better). For the two bitrate modes, QVAL
%   specifies the bitrate in kilobits per second. The supported bitrates
%   are between 8 and 400 kbps.
%
%   NEROAACWRITE(Y,FS,NBITS,QMODE,QVAL,NUMPASS,AACFILE) sets the AAC
%   encoder to run in one-pass (NUMPASS='1pass') or two-pass
%   (NUMPASS='2pass').
%
%   Input Data Ranges
%   The range of values in Y depends on the number of bits specified by
%   NBITS and the data type of Y.  Some examples of valid input ranges
%   based on the value of NBITS and Y's data type are listed in the tables
%   below.
%
%   If Y contains integer data:
%
%       NBITS   Y's data type    Y's Data range          Output Format
%      -------  ---------------- ---------------------   -------------
%         8         uint8             0 <= Y <= 255         uint8
%        16         int16        -32768 <= Y <= +32767      int16
%        24         int32         -2^23 <= Y <= 2^23-1      int32
%
%   If Y contains floating point data:
%
%       NBITS   Y's data type    Y's Data range          Output Format
%      -------  ---------------- ---------------------   -------------
%         8     single or double   -1.0 <= Y <  +1.0        uint8
%        16     single or double   -1.0 <= Y <  +1.0        int16
%        24     single or double   -1.0 <= Y <  +1.0        int32
%        32     single or double   -1.0 <= Y <= +1.0        single
%
%   Note that for floating point data where NBITS < 32, amplitude values
%   are clipped to the range -1.0 <= Y < +1.0.
%
%   NEROAACWRITE(WAVFILE,QMODE,QVAL,NUMPASS,AACFILE) converts the WAVE file
%   specified by WAVFILE, a string enclosed in single quotes. The sampling
%   rate and bit depth of the WAVE file is retained in the AAC file.
%   Similar to other data, 
%
%   See also NEROAACREAD, NEROAACTAG, WAVWRITE.

% Copyright 2012 Takeshi Ikuma
% History:
% rev. - : (10-03-2012) original release

% Parse & check input arguments
[y,fs,nbits,qmode,qval,twopass,wavfile,aacfile,msg] = parse_input(nargin,varargin);
error(msg);

% Retrieve the path
[exefile,msg] = getexepath();
error(msg);

% Set the output file path
if ~ismember(aacfile(1),['.' filesep]) || aacfile(2)==':'
   aacfile = strcat(pwd,filesep,aacfile);
end

genwav = isempty(wavfile);

% resample data if needed
[req2resample,fsnew] = checkfs(fs);
if req2resample
   if ~genwav % wavfile name given, retrieve data first
      [y,fs,nbits] = wavread(wavfile);
      genwav = true; % must create new wave file
   end
   
   y = resample_data(y,fs,fsnew);
   fs = fsnew;
end

% generate wave file name
if genwav
   wavfile = strcat(tempname,'.wav'); % to be deleted
end

% Prepare AAC encoder command
cmd = sprintf('"%s" %s %s %s -if "%s" -of "%s"',exefile,qmode,qval,twopass,wavfile,aacfile);
% neroaacenc [options] -if name of source file -of name of target file
% Quality/bitrate control:
% -q <number>   : Enables "target quality" mode.
%                 <number> is a floating-point number in 0...1 range.
% -br <number>  : Specifies "target bitrate" mode.
%                 <number> is target bitrate in bits per second.
% -cbr <number> : Specifies "target bitrate (streaming)" mode.
%                 <number> is target bitrate in bits per second.
%                 When neither of above quality/bitrate options is used,
%                 the encoder defaults to equivalent of -q 0.5
%
% Multipass encoding:
% -2pass        : Enables two-pass encoding mode.
%                 Note that two-pass more requires a physical file as input,
%                 rather than stdin.
% -2passperiod  : Overrides two-pass encoding bitrate averaging period,
%   <number>    : in milliseconds.
%               : Specify zero to use least restrictive value possible (default).

if genwav % generate wave file first
   wavwrite(y,fs,nbits,wavfile);
end

try
   [status,result] = system(cmd);
   if genwav, delete(wavfile); end % Delete temporary wave file
catch ME
   delete(wavfile);
   rethrow(ME);
end

if status==1
   error(result);
end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [tf,fsnew] = checkfs(fs)
% resample the data if needed

fs_supported = [8000  11025 16000 22050 32000 44100 48000 88200 96000 192000];

I = find(fs_supported>=fs,1,'first'); % determine the nearest next supported sampling rate
if isempty(I) % specified sampling rate too high
   fsnew = fs_supported(end);
else
   fsnew = fs_supported(I);
end

tf = fs~=fsnew; % true if data needs to be resampled

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function y = resample_data(y,fs,fsnew)

% resample
infactors = factor(fs);
outfactors = factor(fsnew);
cmnfactors = intersect(infactors,outfactors);
for n = 1:numel(cmnfactors)
   Iin = find(infactors==cmnfactors(n));
   Iout = find(outfactors==cmnfactors(n));
   Ncmn = min(numel(Iin),numel(Iout));
   infactors(Iin(1:Ncmn)) = [];
   outfactors(Iout(1:Ncmn)) = [];
end

while ~isempty(outfactors) || ~isempty(infactors)
   % set upsampling factor
   P = 1;
   if ~isempty(outfactors)
      Pnext = outfactors(end);
      while Pnext<10
         P = Pnext;
         outfactors(end) = [];
         if isempty(outfactors)
            break;
         end
         
         Pnext = P*outfactors(end);
      end
      fsnew = fs*P;
   end
   
   % set downsampling factor
   Q = 1;
   if ~isempty(infactors)
      Qnext = infactors(1);
      while (P>1 && fsnew/Qnext>fs) || (P==1 && Qnext<10)
         Q = Qnext;
         infactors(1) = [];
         if isempty(infactors)
            break;
         end
         Qnext = Q*infactors(1);
      end
      fsnew = fsnew/Q;
   end
   
   % resample
   y = resample(y,P,Q);
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [exefile,msg] = getexepath()

msg = '';
if ispref('neroaac','encpath')
   exefile = getpref('neroaac','encpath');
   if ~(ischar(exefile) && exist(exefile,'file')) % check to make sure the file exists
      exefile = '';
   end
else
   exefile = '';
end

if isempty(exefile)
   [filename,pathname] = uigetfile({'neroaacenc.exe','Nero AAC Encoder EXE file'},'Locate Nero AAC Encoder EXE file',which('neroaacenc.exe'));
   if (isnumeric(filename) && filename==0) || (isnumeric(pathname) && pathname==0)
      msg = 'User canceled to specify the Nero AAC Encoder executable.';
      return;
   end
   
   exefile = [pathname filename];
   
   setpref('neroaac','encpath',exefile);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [y,fs,nbits,qmode,qval,twopass,wavfile,aacfile,msg] = parse_input(N,argin)

y = [];
fs = 8000;
nbits = 16;
qmode = '-q';
qval = '0.5';
twopass = '';
wavfile = '';
aacfile = '';

msg = nargchk(2,7,N); %#ok
if ~isempty(msg), return; end

% Check source data arguments
if isnumeric(argin{1}) % sample matrix given
   y = argin{1};
   if N>2 && ~isempty(argin{2}) % fs defined
      fs = argin{2};
   end
   if N>3 && ~isempty(argin{3}) % nbits defined
      nbits = argin{3};
   end
   n0 = 4;
elseif ischar(argin{1}) % wavfile given
   if ~ischar(argin{1}) || size(argin{1},1)>1
      msg = 'WAVFILE must be a string of characters.';
      return;
   end
   wavfile = which(argin{1});
   if isempty(wavfile) % if file does not exist, try appending .wav extension
      if isempty(regexp(wavfile,'.wav$','once'))
         wavfile = which(strcat(argin{1},'.wav'));
         if isempty(wavfile)
            msg = 'Invalid Wave File: Cannot open file.';
            return;
         end
      end
   end
   info = audioinfo(wavfile);
   fs = info.SampleRate;
   nbits = info.BitsPerSample;
   n0 = 2;
else
   msg = 'Invalid first argument: neither data matrix nor WAVE file name.';
end

% Check AAC Encoding configuration arguments
if N>n0 && ~isempty(argin{n0}) % qmode defined
   if ~ischar(argin{n0}) || size(argin{n0},1)>1
      msg = 'QMODE must be a string of characters.';
      return;
   end
   qmode = ['-' lower(argin{n0})];
   I = strcmp(qmode,{'-q','-br','-cbr'});
   if ~any(I)
      msg = sprintf('Invalid QMODE given (%s)',qmode);
      return;
   elseif ~I(1) % change default qval to that for bitrates
      qval = '192';
   end
end
n0 = n0+1;
if N>n0 && ~isempty(argin{n0}) % qval defined
   if ~isfloat(argin{n0}) || numel(argin{n0})>1 || isnan(argin{n0}) || isinf(argin{n0})
      msg = ('QVAL must be a finite scalar value.');
      return;
   end
   qval = argin{n0};
   if qmode==1 % quality mode
      if qval<0 || qval>1
         msg = 'QVAL must be between 0 and 1.';
         return;
      end
      qval = sprintf('%0.2f',qval);
   else % bitrate mode
      if qval<8 || qval>400
         msg = 'QVAL must be between 8 and 400.';
         return;
      end
      qval = sprintf('%d',qval * 1000); % convert to bps
   end
end
n0 = n0+1;
if N>n0 && ~isempty(argin{n0}) % twopass defined
   if ~ischar(argin{n0}) || size(argin{n0},1)>1
      msg = 'NUMPASS must be a string of characters.';
      return;
   end
   numpass = strcmpi(argin{n0},{'1pass','2pass'});
   if ~any(numpass)
      msg = sprintf('Invalid NUMPASS given (%s)',numpass);
      return;
   elseif numpass(2)
      twopass = '-2pass';
   end
end

% Check Outputfile
if ~ischar(argin{N}) || size(argin{N},1)>1
   msg = 'AACFILE must be a string of characters.';
   return;
end
aacfile = argin{N};

% if extension not assigned, append '.aac'
if isempty(regexp(aacfile,'[^\.]+\.','once'))
   aacfile = strcat(aacfile,'.m4a');
end

end

Contact us