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)

neroaactag(aacfile,cmdstr,varargin)
function varargout = neroaactag(aacfile,cmdstr,varargin)
%NEROAACTAG Edit Tags in Advanced Audio Coding sound file.
%   NEROAACTAG is a MATLAB wrapper function for Nero AAC Tagger, which is
%   downloadable for free at
%   http://www.nero.com/eng/technologies-aac-codec.html
%
%   NEROAACTAG(AACFILE)
%   NEROAACTAG(AACFILE,'disp'), and
%   NEROAACTAG(AACFILE,'get') display all the stored tag information in an
%   AAC sound file specified by the string AACFILE. The ".m4a" extension is
%   appended if no extension is given.
%
%   V = NEROAACTAG(AACFILE)
%   V = NEROAACTAG(AACFILE,'disp'), and 
%   V = NEROAACTAG(AACFILE,'get') return a structure where each field name
%   is the name of a tag and each field contains the value of that tag.
%
%   V = NEROAACTAG(AACFILE,'get','TagName') returns the value of the
%   specified tag. If 'TagName' is replaced by a cell array of strings
%   containing tag names, then NEROAACTAG will return a matching cell array
%   of values.
%  
%   A = NEROAACTAG(AACFILE,'set') and NEROAACTAG(AACFILE,'set') returns or
%   displays all the user-editable tags. The returned array is a cell array
%   of the names of the editable tags.
%
%   NEROAACTAG(AACFILE,'set','TagName',TagValue) sets the value of the
%   specified tag for the AAC sound file with file name AACFILE. The value
%   must be a string of characters or a numeric array. If a numeric array
%   is given, it is converted to string by NUM2STR function.
%  
%   NEROAACTAG(AACFILE,'set',A) where A is a structure whose field names
%   are tag names, sets the tag named in each tag name with the values
%   contained in the structure.
%  
%   NEROAACTAG(AACFILE,'set',PN,PV) sets the named tags specified in
%   the cell array of strings PN to the corresponding values in the cell
%   array PV.  The cell arrays PN and PV must be vectors with matching
%   dimension.
%  
%   NEROAACTAG(AACFILE,'set','TagName1',TagValue1,'TagName2',TagValue2,...)
%   sets multiple tag values with a single statement.
%
%   See also NEROAACREAD and NEROAACWRITE.

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

% Check input arguments (must have at least 2 arguments)
error(nargchk(1,inf,nargin)); %#ok

% Check file name
if ~ischar(aacfile) || size(aacfile,1)~=1
   error('FILE must be a string of characters.');
end

aacfile = which(aacfile); % expand to full path
if isempty(aacfile) % if file does not exist, try appending .wav extension
   if isempty(regexp(aacfile,'.m4a$','once'))
      aacfile = which(strcat(aacfile,'.m4a'));
      if isempty(aacfile)
         error('Invalid FILE: Cannot open file.');
      end
   end
end

% Check command
if nargin==1
   cmd = 1;
else
   if ~ischar(cmdstr) || size(cmdstr,1)~=1
      error('Invalid CMDSTR: Must be a string of characters.');
   end
   
   cmd = find(strcmpi(cmdstr,{'disp','set','get'}));
   if isempty(cmd)
      error('Invalid CMDSTR: Must be one of ''disp'',''set'', and ''get''.');
   end
end

% initialize the output argument cell
varargout = cell(1,nargout);

try
   % run the command
   switch cmd
      case 1 % disp
         [varargout{:}] = disptag(aacfile,varargin{:});
      case 2 % set
         [varargout{:}] = settag(aacfile,varargin{:});
      case 3 % get
         varargout{1} = gettag(aacfile,varargin{:});
      otherwise       % should never reach here
         error('Invalid CMDSTR: Must be one of ''disp'',''set'', and ''get''.');
   end
catch ME
   rethrow(ME);
end

end

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

function varargout = settag(aacfile,varargin)

% Get valid meta data names
metanames = liststandardmeta();

if nargin==1 % return the list of standard meta field names
   if nargout==0 % display
      fprintf('\n');
      fprintf('    %s\n',metanames{:});
      fprintf('\n');
   else
      varargout{1} = metanames;
   end
   return;
end

% Check input
if iscell(varargin{1}) % if cell input given
   error(nargchk(3,3,nargin)); %#ok
   if ~iscell(varargin{2})
      error('Invalid PV argument: Must be an cell array.');
   end
   fnames = varargin{1};
   fvalues = varargin{2};
   if numel(fnames)~=numel(fvalues)
      error('Invalid PN & PV arguments: Mismatched number of elements.');
   end
elseif isstruct(varargin{1})
   error(nargchk(2,2,nargin)); %#ok
   fnames = fieldnames(varargin{1});
   fvalues = struct2cell(varargin{1});
   N = numel(fnames);
   if numel(fvalues)>N
      error('Invalid A argument: Struct must be scalar.');
   end
else
   error(nargchk(3,inf,nargin)); %#ok
   Narghalf = nargin/2;
   N = floor(Narghalf);
   if N == Narghalf
      error('FieldValue arguments must be given for all PropertyName arguments.')
   end
   fnames = varargin(1:2:end);
   fvalues = varargin(2:2:end);
end

if ~iscellstr(fnames)
   error('Field names must be given in strings of characters.');
end
if ~all(cellfun(@(x)ischar(x)||isnumeric(x),fvalues))
   error('A field value must be given either as a number or as a string of characters.');
end

% Make sure the field names are all supported
[tf,I] = ismember(fnames(:),metanames);
if ~all(tf)
   errmsg = sprintf('%s ',fnames{~tf});
   if sum(~tf)==1
      error('Invalid FieldName: %s',errmsg);
   else
      error('Invalid FieldNames: %s',errmsg);
   end
end

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

% Form AAC tagger command line string
% Usage: 
% neroaactag <file.mp4> <command> [<command> [<command> ...]] 
% Available commands: 
% -meta:<name>=<value>            : Sets specified metadata field to specified 
%                                   value. Eg. -meta:artist="Pink Floyd" 
cmd = sprintf('"%s" "%s"',exefile,aacfile);
for n = 1:N
   if ischar(fvalues{n})
      val = fvalues{n};
   else
      val = num2str(fvalues{n});
   end
   cmd = sprintf('%s -meta:%s=%s',cmd,fnames{I(n)},val);
end

[status,result] = system(cmd);
if status==1
   error(result);
end

end

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

function varargout = gettag(aacfile,varargin)

% if no meta data name given, perform 'disp' command instead
if nargin==1
   varargout = cell(1,nargout);
   [varargout{:}] = disptag(aacfile);
   return;
end

% check input
error(nargchk(2,2,nargin)); %#ok

switch class(varargin{1})
   case 'char'
      IsChar = true;
      fnames = lower(varargin(1));
   case 'cell'
      IsChar = false;
      fnames = lower(varargin{1});
   otherwise
      error('Invalid Object for PropertyName');
end

% Get meta data
metadata = listmeta(aacfile);

% Lookfor the metadata name
[tf,I] = ismember(fnames(:),metadata(1,:));
if ~all(tf)
   errmsg = sprintf('%s ',fnames{~tf});
   if sum(~tf)==1
      error('Invalid PropertyName: %s',errmsg);
   else
      error('Invalid PropertyNames: %s',errmsg);
   end
end

% Return the property values
if IsChar
   varargout(1) = metadata(2,I);
else
   varargout{1} = reshape(metadata(2,I),size(fnames));
end

end

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

function varargout = disptag(aacfile,varargin)

% Get meta data
metadata = listmeta(aacfile);

if nargout==0 % display
   Nfn = cellfun(@numel,metadata(1,:));
   Nmax = max(Nfn);
   fprintf('\n');
   for n = 1:size(metadata,2)
      fprintf('    %s%s: %s\n',repmat(' ',1,Nmax-Nfn(n)),metadata{1,n},metadata{2,n});
   end
   fprintf('\n');
else % output struct
   varargout{1} = struct(metadata{:});
end

end

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

function metadata = listmeta(aacfile)
% returns metadata in a cell array of strings

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

% Prepare AAC tagger command
% Usage: 
% neroaactag <file.mp4> <command>
% Available commands: 
% -list-meta                      : Lists existing metadata entries. 
% -list-covers                    : Lists cover art entries. 

[status,result] = system(sprintf('"%s" "%s" -list-meta',exefile,aacfile));
if status==1
   error(result);
end

% Get meta data

I = regexp(result,'Metadata list:\s+','end','once');
result(1:I) = [];

I = regexp(result,'\s+End of metadata.','start','once');
result(I:end) = [];

data = textscan(result,'%s','Delimiter',char(10));
metadata = regexp(data{1},'\s*(\S+) = (.*)','tokens','once');
metadata = reshape([metadata{:}],2,numel(metadata));

end

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

function metanames = liststandardmeta()
% returns metadata in a cell array of strings

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

% Prepare AAC tagger command
% Usage: 
% neroaactag <file.mp4> <command>
% Available commands: 
% -list-standard-meta             : Displays a list of field names usable with 
%                                   -meta command. 
[status,result] = system(sprintf('"%s" -list-standard-meta',exefile));
if status==1
   error(result);
end

% Get meta data

I = regexp(result,'List of standard Nero Digital metadata field names:\s+','end','once');
result(1:I) = [];

I = regexp(result,'\s+End of metadata field name list.','start','once');
result(I:end) = [];

metanames = subsref(textscan(result,'%s'),struct('type','{}','subs',{{1,1}}));

end

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

function [exefile,msg] = getexepath()

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

if isempty(exefile)
   [filename,pathname] = uigetfile({'neroaactag.exe','Nero AAC Tagger EXE file'},'Locate Nero AAC Tagger EXE file',which('neroaactag.exe'));
   if (isnumeric(filename) && filename==0) || (isnumeric(pathname) && pathname==0)
      msg = 'User canceled to specify the Nero AAC tagger executable.';
      return;
   end
   
   exefile = [pathname filename];
   
   setpref('neroaac','tagpath',exefile);
end
end

Contact us