function [shiftedPv, shiftAmount, bestRatio]=bestKeyTranspose(pv, opt, showPlot) % Shift the pitch to a position with most white keys % % Usage: % [shiftedPv, bestShiftAmount]=bestKeyTranspose(pv, opt, showPlot) % % Example: % pv=[55.79;55.79;55.79;55.79;55.79;55.79;55.79;56.01;56.24;56.47;56.47;56.47;0;0;0;0;0;60.62;60.92;61.22;61.22;61.22;61.22;61.22;0;0;0;0;0;0;63.14;63.49;63.49;63.49;63.49;63.84;64.56;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;64.56;64.93;64.93;65.7;66.92;67.79;67.79;67.79;67.79;67.79;67.35;65.7;65.31;65.31;65.31;65.31;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.93;64.56;64.56;0;0;0;0;0;0;0;0;0;0;0;0;60.62;60.62;60.92;60.92;61.22;61.84;62.48;62.48;62.48;62.48;0;0;0;60.92;60.92;60.92;60.92;60.92;60.92;60.92;60.92;60.92;60.92;0;0;0;0;59.49;59.49;59.49;59.49;59.76;60.04;60.33;60.62;60.92;60.92;60.92;61.22;61.22;61.22;60.92;60.92;60.92;60.92;60.92;60.92;60.92;60.92;60.62;60.33;60.04;59.76;59.49;59.76;59.76;59.76;60.04;60.33;60.33;60.33;60.33;60.04;59.76;58.68;58.16;57.91;57.91;57.91;57.66;57.42;57.17;56.94;56.7;56.47;56.24;56.24;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;56.01;0;0;0;0;0;0]; % pv=[56 61 65 68 65 63 61 61 61 61 58 56]; % opt=bestKeyTranspose('defaultOpt'); % [shiftedPv, shiftAmount]=bestKeyTranspose(pv, opt, 1); % Category: Music processing % Roger Jang, 20200621 if nargin<1, selfdemo; return; end if ischar(pv) && strcmpi(pv, 'defaultOpt') % Set the default options shiftedPv.shiftVec=-6:1:6; return end if nargin<2||isempty(opt), opt=feval(mfilename, 'defaultOpt'); end if nargin<3, showPlot=0; end pvLen=length(pv); pv(pv==0 | isnan(pv))=[]; for i=1:length(opt.shiftVec) pv2=pv+opt.shiftVec(i); id=isWhiteKey(round(pv2)); whiteRatio(i)=sum(id)/pvLen; end % Find the shift that is closed to zero [bestRatio, index]=max(whiteRatio); index=find(whiteRatio==bestRatio); [~, id]=min(abs(opt.shiftVec(index))); shiftAmount=opt.shiftVec(index(id)); shiftedPv=pv+shiftAmount; if showPlot bar(opt.shiftVec, whiteRatio); xlabel('Shifted amount'); ylabel('Ratio of white keys'); line(shiftAmount, bestRatio, 'marker', '^', 'color', 'r'); fprintf('Best shift=%g semitone, best ratio=%g%%\n', shiftAmount, 100*bestRatio); end % ====== Self demo function selfdemo mObj=mFileParse(which(mfilename)); strEval(mObj.example);