function [I,oct] = note2interval(N,key)
% MUSIC.NOTE2INTERVAL Converts a note string to a semitone interval and octave.
% [I,O] = MUSIC.NOTE2INTERVAL(N) returns the interval I and octave O at which
% note N is found in the key of 'C'. N is a note in scientific pitch notation
% (e.g. 'A#3') or a simple note string without an octave specification (e.g.
% 'A#'). If the octave is not defined O will be NaN. N may be a cell array of
% strings.
%
% [I,O] = MUSIC.NOTE2INTERVAL(N,KEY) returns the interval at which note N is
% found in the key of KEY. KEY may be a character note (e.g., 'A', 'F#'), or
% an interval offset from 'C'.
%
% Example
% [I,O] = music.note2interval('F#') % returns 6, NaN
% [I,O] = music.note2interval('F#5','G') % returns 11, 5
%
% See also music.note2tone, music.note2freq, music.interval2note.
% Author: E. Johnson
% Copyright 2010 The MathWorks, Inc.
% Resolve character key to offset from C
if nargin < 2
key = 0;
end
if ischar(key)
key = music.note2interval(key);
end
% The interval offset from the beginning of the notes octave, can be used to
% index into this table. Which column is used depends on whether or not the key
% is expressed using sharps or flats.
noteTable = { 'C' 'C' ;
'C#' 'Db';
'D' 'D' ;
'D#' 'Eb';
'E' 'E' ;
'F' 'F' ;
'F#' 'Gb';
'G' 'G' ;
'G#' 'Ab';
'A' 'A' ;
'A#' 'Bb';
'B' 'B' ; };
N = cellstr(N); % ensure N is a cell array
sz = size(N); % record original size of N
N = N(:); % ensure N is a column vector
% Use regular expression to separate octave from note.
C = regexp(N,'([AaBbCcDdEeFfGg][Bb#]?)(\d*$)','tokens');
note = cellfun( @(c)c{1}{1}, C, 'UniformOutput', false ); % simple note
oct = cellfun( @(c)str2double(c{1}{2}), C ); % octave
ind = cellfun(@(n)find(strcmpi(noteTable,n),1),note);
[row,col] = ind2sub(size(noteTable),ind); %#ok
I = row - 1 - key;
I = mod(I,12);
I = reshape(I, sz);
oct = reshape(oct,sz);