%CHORD ANALYZER PROGRAM version 2 - Mapping unknown File to Chord

data = dlmread('database.txt');
unknown = input('Input name of file wrapped in single quotes: ');

%%EXTRACTING MAX 5 PEAKS FROM UNKNOWN
[x, Fs] = wavread(unknown);
l = length(x);
NFFT = 2^nextpow2(l);
X = abs(fft(x,NFFT));
f=Fs/2*linspace(0,1,NFFT/2);
XdB = 20*log10(X);
len = length(XdB);

%figure;
%plot(f,XdB(1:NFFT/2));
%title('Amplitude Spectrum of chord in dB');
%xlabel('Frequency (Hz)');
%ylabel('|X(f)| (dB)');
%legend(unknown);

[val, idx] = max(XdB(floor(100*len/Fs):floor(len/2)));
idx=idx+100*len/Fs - 1;
idx=idx*Fs/len;

peaks = 0;
indices = 0;
j=1;
for i = floor(100*len/Fs):floor(len/2), 
    if(XdB(i)>(val-20))
        if(XdB(i)>XdB(i-1) & XdB(i)>=XdB(i+1)) 
            peaks(j)=XdB(i);
            tmp=find(XdB==XdB(i));
            indices(j)=(tmp(1)-1)*Fs/len;
            j=j+1;
        end
    end
end

pks=0;
inds=0;
j=1;
i=1;
while(i<=length(peaks)),
    k=i+1;
    %%5HZ IS OPTIMAL??
    while(k<length(peaks) & (indices(k)-indices(i))<5) %if within 5 Hz of each other
        k=k+1;
    end
    s=max(peaks(i:k-1));
    pks(j)=s;
    tmp=find(XdB==s);
    inds(j)=(tmp(1)-1)*Fs/len;
    j=j+1;
    i=k;
end

max_freq=[idx]; 
[sorted,j]=sort(pks); 
for i=1:length(sorted)-1,
    if(abs(inds(j(end-i)) - max_freq) > 5) 
        max_freq(i+1)=inds(j(end-i));
    else
        tmp=find(not((abs(inds(j(end-i)) - max_freq)>5)));
        if(pks(j(end-i)>pks(tmp)))
            max_freq(i+1)=inds(j(end-i));
        end
    end
end
max_freq(max_freq==0)=[]; 
final_freq = max_freq(1:5);
%final_freq now holds max 5 peaks
%max_freq stores all max peaks within 20 dB

%%%%%%%Comparing 5 max peaks of unknown to stored values%%%%%%%%
hash = 0;
confidence = 0; %like a 5-star system
%Looking for perfect match
N = size(data);
for i=1:N(1)
    if(abs(final_freq - data(i,:)) < 5) %if each peak is within 5 Hz
        hash = i;
        confidence = 5;
        break;
    end
end

%NO DIRECT MATCH
%Try sorting 5 max peaks by freq and looking for match
if(confidence == 0)
    sorted_data=sort(data,2);
    sorted_ff=sort(final_freq);
    for i=1:N(1)
        if(abs(sorted_ff - sorted_data(i,:)) < 5)
            hash = i;
            confidence = 4;
            break;
        end
    end  
end

%If still no luck, try second run through on stored data
    %to see if anything is close (i.e. 4 out of 5)
if(confidence == 0)
    for i=1:N(1)
        cnt=0;
        for k=1:5
            if(abs(final_freq(k) - data(i,k)) < 5)
                cnt = cnt+1;
            end
            if (cnt==4)
                hash = i;
                break
            end
        end
        if(cnt==4)
            confidence = 3;
            break
        end
    end
end

%last attempt: 4/5 matches, when sorted
if(confidence == 0)
    for i=1:N(1)
        cnt=0;
        for k=1:5
            if(abs(sorted_ff(k) - sorted_data(i,k)) < 5)
                cnt = cnt+1;
            end
            if (cnt==4)
                hash = i;
                break
            end
        end
        if(cnt==4)
            confidence = 2;
            break
        end
    end
end
    
    
%%%DISPLAYING RESULTS%%%
if(hash~=0)
    name = hash_table(hash);
    rating = conf(confidence);
    sprintf('The chord you played was %s \n%s according to data matching', name, rating)
else
    disp('No matches found')
end


 




%%%%%%%%%%%%%%%%%DYNAMIC PROGRAM%%%%%%%%%%%%%%%%%%%%%%%%
sorted_max=sort(max_freq);
max_freq = sort(max_freq); %debugging purposes

%not checking frequencies over 1000 Hz becuase innacurate matching
%sorted_max(find(sorted_max>1000))=0;
sorted_max(sorted_max==0)=[];
check = zeros(1,length(sorted_max));
for i = 1:length(sorted_max)
    if(sorted_max(i)==1)
        continue;
    else
        h=find(abs(sorted_max-sorted_max(i)*2)<7); %find same note an octave higher
        l=find(abs(sorted_max-sorted_max(i)/2)<5); %find same note an octave lower
        if(h&l)
            check(i)=1;
        end
        %if(h)
        %  check(h)=1;
        %  check(i)=1;
        %end
        %if(l)
        %    check(l)=1;
        %    check(i)=1;
        %end
    end
end
sorted_max(find(~check))=0;
sorted_max(sorted_max==0)=[];
%just looking within one octave
if(find(sorted_max<320))
    sorted_max(find(sorted_max<320))=sorted_max(find(sorted_max<320))*2;
end
if(find(sorted_max>630))
    sorted_max(find(sorted_max>630))=sorted_max(find(sorted_max>630))/2;
end
%eliminating repeats
sorted_max=sort(sorted_max);
for i=1:length(sorted_max)-1,
    if(sorted_max(i+1)-sorted_max(i)>0 & sorted_max(i+1)-sorted_max(i)<7)
        sorted_max(i)=0;
    end
end
sorted_max(sorted_max==0)=[];
%sorted_max(find(sorted_max<320))=0;
%sorted_max(find(sorted_max>630))=0;



%Storing the actual notes of the chord
notes=[];
for i=1:length(sorted_max)
    [note,add]=freq_table(sorted_max(i));
    notes=[notes; note];
    adder(i)=add;
end

%Looking for maj/min patterns
list = ['E    ';'F    ';'F#/Gb';'G    ';'G#/Ab';'A    ';'A#/Bb';'B    ';'C    ';'C#/Db';'D    ';'D#/Eb';'E    ';'F    ';'F#/Gb';'G    ';'G#/Ab';'A    ';'A#/Bb';'B    ';'C    ';'C#/Db';'D    '];
answer=0;
for i=1:size(notes,1)
    if(size(notes,1)==3)
        %major pattern: R 3 5
        major=[list(adder(i),:);list(adder(i)+4,:);list(adder(i)+7,:)];
        if(sort(major,1) == sort(notes,1))
            sprintf('Your chord is %s %s \nwith a confidence rating of VERY CONFIDENT according to frequency matching',num2str(list(adder(i))),'major')
            answer=1;
            break;
        end
        %minor pattern: R 3b 5
        minor=[list(adder(i),:);list(adder(i)+3,:);list(adder(i)+7,:)];
        if(sort(minor,1) == sort(notes,1))
            sprintf('Your chord is %s %s \nwith a confidence rating of VERY CONFIDENT according to frequency matching',num2str(list(adder(i))),'minor')
            answer=1;
            break;
        end
    elseif(size(notes,1)==4)
        %major-7 pattern: R 3 5 7b
        major7=[list(adder(i),:);list(adder(i)+4,:);list(adder(i)+7,:);list(adder(i)+10,:)];
        if(sort(major7,1) == sort(notes,1))
            sprintf('Your chord is %s %s \nwith a confidence rating of VERY CONFIDENT according to frequency matching',num2str(list(adder(i))),'major7')
            answer=1;
            break;
        end
        %minor-7 pattern: R 3b 5 7b
        minor7=[list(adder(i),:);list(adder(i)+3,:);list(adder(i)+7,:);list(adder(i)+10,:)];
        if(sort(minor7,1) == sort(notes,1))
            sprintf('Your chord is %s %s \nwith a confidence rating of VERY CONFIDENT according to frequency matching',num2str(list(adder(i))),'minor7')
            answer=1;
            break;
        end
    elseif(size(notes,1)==2)
        %only have two notes, try to guess what third could be
        %find which place in list each notes lies
        tempor=find(list(:,1)==notes(1,1));
        tempor(find(list(tempor,2)==notes(1,2)));
        tempor2=find(list(:,1)==notes(2,1));
        tempor2(find(list(tempor2,2)==notes(1,2)));
        %take difference
        diff=tempor2(1)-tempor(1);
        
        %pin to model
        if (diff==3)
            %most likely missing 5th in minor chord
            notes(3,:)=list(adder(1)+7,:);
            sprintf('The 2 notes that match are %s %s;\n The third is most likely %s to complete the minor chord\n with a confidence level of MOST LIKELY according to frequency matching', num2str(notes(1,:)), num2str(notes(2,:)),num2str(notes(3,:)))
            answer=1;
        elseif (diff==4)
            %most likely missing 5th in major chord
            notes(3,:)=list(adder(1)+7,:);
            sprintf('The 2 notes that match are %s %s;\n The third is most likely %s to complete the major chord\n with a confidence level of MOST LIKELY according to frequency matching', num2str(notes(1,:)), num2str(notes(2,:)),num2str(notes(3,:)))
            answer=1;
        elseif (diff==7)
            %missing 3rd either in major or minor
            notes(3,:)=list(adder(1)+4,:); %maj
            notes(4,:)=list(adder(1)+3,:); %min
            sprintf('The 2 notes that match are\n %s %s\n The third is most likely\n %s to complete the major chord or \n %s to complete the minor chord\n with a confidence level of LIKELY according to frequency matching', num2str(notes(1,:)), num2str(notes(2,:)), num2str(notes(3,:)), num2str(notes(4,:)))
            answer=1;
        end
        break;
    else        
        disp('error with length of notes array')
        break;
    end
end
   
if(answer~=1)
    disp('No dynamic match')
    notes
end
    
    

%%CHANGE RATING SYSTEM TO SEE IF DYNAMIC AND STATIC ARE IN AGREEMENT
    

%close all files
ST = fclose('all');