computes the chords of the input audio (super simple variant) > > @param x: time domain sample data, dimension samples X channels > @param f_s: sample rate of audio data > @param iBlockLength: internal block length (default: 4096 samples) > @param iHopLength: internal hop length (default: 2048 samples) > > @retval cChordLabel likeliest chord string (e.g., C Maj) > @retval iChordIdx likeliest chord index (Major: 0:11, minor: 12:23, starting from C, dimensions 2 X number of blocks: first row are the raw results without post-processing, second row are the postprocessed results) > @retval t timestamps for each result (length blocks) > @retval afChordProbs raw chord probability matrix (dimension 24 X blocks) ======================================================================
0001 %computes the chords of the input audio (super simple variant) 0002 %> 0003 %> @param x: time domain sample data, dimension samples X channels 0004 %> @param f_s: sample rate of audio data 0005 %> @param iBlockLength: internal block length (default: 4096 samples) 0006 %> @param iHopLength: internal hop length (default: 2048 samples) 0007 %> 0008 %> @retval cChordLabel likeliest chord string (e.g., C Maj) 0009 %> @retval iChordIdx likeliest chord index (Major: 0:11, minor: 12:23, starting from C, dimensions 2 X number of blocks: first row are the raw results without post-processing, second row are the postprocessed results) 0010 %> @retval t timestamps for each result (length blocks) 0011 %> @retval afChordProbs raw chord probability matrix (dimension 24 X blocks) 0012 % ====================================================================== 0013 function [cChordLabel, aiChordIdx, t, P_E] = ComputeChords (x, f_s, iBlockLength, iHopLength) 0014 0015 % set default parameters if necessary 0016 if (nargin < 5) 0017 iHopLength = 2048; 0018 end 0019 if (nargin < 4) 0020 iBlockLength = 8192; 0021 end 0022 0023 % chord names 0024 cChords = char ('C Maj','C# Maj','D Maj','D# Maj','E Maj','F Maj',... 0025 'F# Maj','G Maj','G# Maj','A Maj','A# Maj','B Maj', 'c min',... 0026 'c# min','d min','d# min','e min','f min','f# min','g min',... 0027 'g# min','a min','a# min','b min'); 0028 0029 % chord templates 0030 [T] = generateTemplateMatrix_I (); 0031 0032 % transition probabilities 0033 [P_T] = getChordTransProb_I (); 0034 0035 % pre-processing: normalization 0036 x = ToolNormalizeAudio(x); 0037 0038 % extract pitch chroma 0039 [v_pc, t] = ComputeFeature ('SpectralPitchChroma',... 0040 x,... 0041 f_s,... 0042 [],... 0043 iBlockLength,... 0044 iHopLength); 0045 0046 % estimate chord probabilities 0047 P_E = T * v_pc; 0048 P_E = P_E ./ sum(P_E, 1); 0049 0050 % assign series of labels/indices starting with 0 0051 aiChordIdx = zeros(2, length(t)); 0052 [~, aiChordIdx(1,:)] = max(P_E, [], 1); 0053 0054 % compute path with Viterbi algorithm 0055 [aiChordIdx(2,:), ~] = ToolViterbi(P_E,... 0056 P_T,... 0057 ones(length(cChords),1)/length(cChords),... 0058 true); 0059 0060 % assign result string 0061 cChordLabel = deblank(cChords(aiChordIdx,:)); 0062 % we want to start with 0! 0063 aiChordIdx = aiChordIdx - 1; 0064 end 0065 0066 function [T] = generateTemplateMatrix_I () 0067 0068 % init: 12 major and 12 minor triads 0069 T = zeros(24,12); 0070 0071 % all chord pitches are weighted equally 0072 T(1, [1 5 8]) = 1/3; 0073 T(13, [1 4 8]) = 1/3; 0074 0075 % generate templates for all root notes 0076 for i = 1:11 0077 T(i+1, :) = circshift(T(i, :), 1, 2); 0078 T(i+13, :) = circshift(T(i+12, :), 1, 2); 0079 end 0080 end 0081 0082 function [P_T] = getChordTransProb_I() 0083 0084 % circle of fifth tonic distances 0085 circ = [0 -5 2 -3 4 -1 6 1 -4 3 -2 5,... 0086 -3 4 -1 6 1 -4 3 -2 5 0 -5 2]; 0087 0088 % set the circle radius and distance 0089 R = 1; 0090 d = .5; 0091 0092 % generate key coordinates (mode in z) 0093 x = R * cos(2 * pi * circ / 12); 0094 y = R * sin(2 * pi * circ / 12); 0095 z = [d * ones(1,12),... 0096 zeros(1,12)]; 0097 0098 % compute key distances 0099 for (m = 1:size(x, 2)) 0100 for (n = 1:size(x, 2)) 0101 P_T(m, n) = sqrt((x(m)-x(n))^2 + (y(m)-y(n))^2 + (z(m)-z(n))^2); 0102 end 0103 end 0104 0105 % convert distances into 'probabilities' 0106 P_T = .1 + P_T; 0107 P_T = 1 - P_T / (.1 + max(max(P_T))); 0108 P_T = P_T ./ sum(P_T, 1); 0109 end