function D = en_analyze(F, verbose)
% D = en_analyze(F, verbose)
%     Pass an MP3 file whose filename is F to the Echo Nest
%     Analyze API, and return the analyzed data.
%     If F is a "music:TR..." key, skip upload and query that track.
%     F can also be the bytes of an MP3 file (if of type uint8).
%
%     This version uses Analyze v4 and json format for data return.
%     It relies on p_json.m .
% 2011-04-11 Dan Ellis dpwe@ee.columbia.edu

API_KEY='9UGMUXTCZ2WT7WWMJ';  % E4896 key

if nargin < 2
  verbose = 0;
end

if isnumeric(F) || strncmp(F, 'music:', 6)==0

  if isa(F,'uint8')
    % F is the bytes read from an mp3 file
    d = F;
  else
    if isnumeric(F)
      % maybe accept a waveform - but then we'd need a sampling
      % rate.  We'd have to mp3write it to a temporary file, then
      % upload that.
      error('F was numeric but not bytes - unrecognized type');
    end
    % We were passed an actual file name
    % Read in the MP3 file
    f = fopen(F);
    d = fread(f,Inf,'*uint8');  % Read in byte stream of MP3 file
    fclose(f);
  end

  ddisp('uploading mp3', verbose);

  % Post to EN Analyze
  % readpost with single argument posts an octet-stream, as
  % required for v4; rest of args go into URL
  str = urlpostdata('http://developer.echonest.com/api/v4/track/upload', ...
                    {'api_key',API_KEY,'filetype','mp3', ...
                     'wait','true','format','json'}, ...
                    d);

  ddisp('upload complete', verbose);

  % Grab return
  ret = p_json(str);

  % Check EN fields
  retcode = ret.response.status.code;
  if retcode ~= 0  % ret.status.code
   disp(['******* upload returned ', num2str(retcode), 
         ' - ',ret.response.status.message]);
   D = [];
   return
  end

  % Get track ID
  track = ret.response.track.id;
  % always report track ID
else
  if strncmp(F, 'music:', 6)
    F = F(7:end);
    if max(F=='/') > 0
      F = F(max(find(F=='/'))+1:end);
    end
  end
  track = F;
end
  
disp(['track ID=',track]);
D.id = track;

% read back the entire analysis structure
%str = urlreadpost('http://developer.echonest.com/api/v4/track/analyze', ...
%                  {'api_key',API_KEY,'format','json','id',track, ...
%                   'bucket','audio_summary','wait','true'});
str = urlread(['http://developer.echonest.com/api/v4/track/profile?', ...
               'api_key=',API_KEY,'&format=','json','&id=',track, ...
                   '&bucket=','audio_summary']);
ddisp('got analyze response', verbose);

% find the full analysis structure
ret = p_json(str);

trackinfo = ret.response.track;

analysis_url = trackinfo.audio_summary.analysis_url;
str = urlread(analysis_url);
ddisp('got analysis url data', verbose);

analysis = p_json(str);
ddisp('parsed analysis url data', verbose);

nsegs = length(analysis.segments);
nchr = length(analysis.segments{1}.pitches);
ntimb = length(analysis.segments{1}.timbre);

D.pitches = zeros(nchr, nsegs);
D.timbre = zeros(ntimb, nsegs);
D.segment = zeros(1, nsegs);
D.segmentduration = zeros(1, nsegs);
D.segmentloudness = zeros(1, nsegs);
D.segmentloudnessmax = zeros(1, nsegs);
D.segmentloudnessmaxtime = zeros(1, nsegs);

%Trial>> str2num(analysis(5).sub(2).sub(3).sub(1).data)
% 3rd chroma coef of 5th frame

for i = 1:nsegs
  D.pitches(:,i) = cellfun(@(x) x, analysis.segments{i}.pitches)';
  D.timbre(:,i) = cellfun(@(x) x, analysis.segments{i}.timbre)';
%  D.segment(i) = d.analysis.segment(i).ATTRIBUTE.start;  % D.segment or D.segmentstart?
%  D.segmentduration(i) = d.analysis.segment(i).ATTRIBUTE.duration;
%  D.segmentloudness(i) = d.analysis.segment(i).loudness.dB(1).CONTENT;
%  D.segmentloudnessmax(i) = d.analysis.segment(i).loudness.dB(2).CONTENT;
%  D.segmentloudnessmaxtime(i) = d.analysis.segment(i).loudness.dB(2).ATTRIBUTE.time;
end

D.segment = cellfun(@(x) x.start, analysis.segments);
D.segmentduration = cellfun(@(x) x.duration, analysis.segments);
D.segmentloudness = cellfun(@(x) x.loudness_start, analysis.segments);
D.segmentloudnessmax = cellfun(@(x) x.loudness_max, analysis.segments);
D.segmentloudnessmaxtime = cellfun(@(x) x.loudness_max_time, analysis.segments);

ddisp('segment info parsed', verbose);

% Read the tatums
%ntatums = length(d.analysis.tatum);
ntatums = length(analysis.tatums);
D.tatum = cellfun(@(x) x.start, analysis.tatums);
D.tatumconfidence = cellfun(@(x) x.confidence, analysis.tatums);

% Read the beats
nbeats = length(analysis.beats);
D.beat = cellfun(@(x) x.start, analysis.beats);
D.beatconfidence = cellfun(@(x) x.confidence, analysis.beats);

ddisp('beat info parsed', verbose);

% Read the bars
nbars = length(analysis.bars);
D.bar = cellfun(@(x) x.start, analysis.bars);
D.barconfidence = cellfun(@(x) x.confidence, analysis.bars);

ddisp('bar info parsed', verbose);

% Read the sections
nsections = length(analysis.sections);
D.section = cellfun(@(x) x.start, analysis.sections);
D.sectionduration = cellfun(@(x) x.duration, analysis.sections);
D.sectionconfidence = cellfun(@(x) x.confidence, analysis.sections);

ddisp(' parsing remaining fields', verbose);

% Single value attributes
D.end_of_fade_in = analysis.track.end_of_fade_in;
D.start_of_fade_out = analysis.track.start_of_fade_out;
D.key = analysis.track.key;
D.keyconfidence = analysis.track.key_confidence;
D.mode = analysis.track.mode;
D.modeconfidence = analysis.track.mode_confidence;
D.loudness = analysis.track.loudness;
D.tempo = analysis.track.tempo;
D.tempoconfidence = analysis.track.tempo_confidence;
D.time_signature = analysis.track.time_signature;
D.time_signatureconfidence = analysis.track.time_signature_confidence;

% Metadata
% Set whatever we get, but ensure artist, release, and title exist
D.artist = '';
D.release = '';
D.title = '';

metafield = fieldnames(trackinfo);
for i = 1:length(metafield)
  field = metafield{i};
  val = getfield(trackinfo,field);
  if ~isstruct(val)
    D = setfield(D,field,val);
  end
end
% and for audio_summary fields
metafield = fieldnames(trackinfo.audio_summary);
for i = 1:length(metafield)
  field = metafield{i};
  val = getfield(trackinfo.audio_summary,field);
  if ~isstruct(val)
    D = setfield(D,field,val);
  end
end

ddisp('done', verbose);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ddisp(s,v)
if(v) 
  disp(s)
end
