Home > ACA-Code > ComputeChords.m

ComputeChords

PURPOSE ^

computes the chords of the input audio (super simple variant)

SYNOPSIS ^

function [cChordLabel, aiChordIdx, t, P_E] = ComputeChords (x, f_s, iBlockLength, iHopLength)

DESCRIPTION ^

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)
 ======================================================================

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

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

Generated on Fri 22-Apr-2022 20:59:51 by m2html © 2005