christopherh@1: % christopherh@1: %PARSECHORD parse chord symbol to its constituent string elements christopherh@1: % christopherh@1: % [rootnote, shorthand, intervals, bass, success, errormessage] christopherh@1: % = parsechord(chord, {verbose}) christopherh@1: % christopherh@1: % Parses the chord symbol string "chord" into its separate string elements. christopherh@1: % christopherh@1: % NOTE: This function does not check validity of the chord elements, it christopherh@1: % merely separates them according to the chord syntax. christopherh@1: % To obtain chord elements with included validity check use GETCHORDINFO. christopherh@1: % christopherh@1: % Success = 1 if symbols parsed correctly, 0 otherwise. christopherh@1: % christopherh@1: % If optional argument 'verbose' is 1, function prints any errormessage to christopherh@1: % the screen. christopherh@1: % christopherh@1: % returns: rootnote (note string) christopherh@1: % shorthand (shorthand string) christopherh@1: % intervals (interval-list string) christopherh@1: % bass (interval string) christopherh@1: % success (boolean) christopherh@1: % errormessage (string) christopherh@1: % christopherh@1: % See also: getchordinfo christopherh@1: % christopherh@1: % Author: Christopher Harte, March 2009 christopherh@1: % christopherh@1: % Copyright: Centre for Digital Music, Queen Mary University of London 2005 christopherh@1: % christopherh@1: % This file is part of the C4DM Chord Toolkit V2.0 christopherh@1: % christopherh@1: % The C4DM Chord Toolkit is free software; you can redistribute it and/or christopherh@1: % modify it under the terms of the GNU General Public License as published christopherh@1: % by the Free Software Foundation; either version 2 of the License, or christopherh@1: % (at your option) any later version. christopherh@1: % christopherh@1: % The C4DM Chord Toolkit is distributed in the hope that it will be useful, christopherh@1: % but WITHOUT ANY WARRANTY; without even the implied warranty of christopherh@1: % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the christopherh@1: % GNU General Public License for more details. christopherh@1: % christopherh@1: % You should have received a copy of the GNU General Public License christopherh@1: % along with the C4DM Toolkit; if not, write to the Free Software christopherh@1: % Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA christopherh@1: christopherh@1: % christopherh@1: function [rootnote, shorthand, intervals, bass, success, errormessage] = parsechord(chord, verbose) christopherh@1: christopherh@1: % set verbose default to 0 christopherh@1: if nargin <2 christopherh@1: verbose = 0; christopherh@1: end christopherh@1: christopherh@1: ilength = length(chord); christopherh@1: christopherh@1: % initialise variables christopherh@1: errormessage = ''; christopherh@1: rootnote = ''; christopherh@1: shorthand = ''; christopherh@1: intervals = ''; christopherh@1: bass = ''; christopherh@1: christopherh@1: success = 1; christopherh@1: index = 1; christopherh@1: christopherh@1: christopherh@1: % check for 'no chord' symbol christopherh@1: if chord(index) == 'N' christopherh@1: rootnote = chord(index); christopherh@1: index = index +1; christopherh@1: % check to see there are no further characters christopherh@1: if(index<=ilength) christopherh@1: errormessage = sprintf(['Error in parsechord: \nExtra characters after "no chord" symbol "' chord '"\n']); christopherh@1: success = 0; christopherh@1: end christopherh@1: else christopherh@1: % parse thechord symbol christopherh@1: christopherh@1: % the first part of the symbol before a switch character should be the root note christopherh@1: while ((index <=ilength )) christopherh@1: christopherh@1: if (chord(index) == ':') || (chord(index) == '/') || ... christopherh@1: (chord(index) == '(') || (chord(index) == ')') christopherh@1: christopherh@1: break christopherh@1: end christopherh@1: christopherh@1: rootnote(index) = chord(index); christopherh@1: index = index+1; christopherh@1: christopherh@1: if(index > ilength) || (chord(index) == '/') christopherh@1: % if chord is a rootnote on its own or with just a bass note christopherh@1: % then it is a major chord therefore set shorthand to 'maj' christopherh@1: shorthand = 'maj'; christopherh@1: end christopherh@1: end christopherh@1: christopherh@1: % initialise booleans to record which switch characters we have found christopherh@1: colon = 0; christopherh@1: openbracket = 0; christopherh@1: closebracket = 0; christopherh@1: slash = 0; christopherh@1: christopherh@1: % parse the rest of the chord symbol christopherh@1: while(index <= ilength) christopherh@1: christopherh@1: % reset temporary index christopherh@1: tempindex = 1; christopherh@1: christopherh@1: switch(chord(index)) christopherh@1: christopherh@1: case ':' christopherh@1: christopherh@1: % if we find a colon after any switch characters have christopherh@1: % already occured then the symbol is incorrect christopherh@1: if (colon || openbracket || closebracket || slash) christopherh@1: errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength+1; christopherh@1: else christopherh@1: christopherh@1: % found the first instance of a colon character christopherh@1: colon = 1; christopherh@1: christopherh@1: index = index +1; christopherh@1: christopherh@1: if(index > ilength) christopherh@1: errormessage = sprintf(['Error in parsechord: \nFound ":" at end of chord string "' chord '"\n']); christopherh@1: success = 0; christopherh@1: end christopherh@1: % colon should be followed by a shorthand string or christopherh@1: % an interval list contained in brackets christopherh@1: while (index <= ilength) christopherh@1: christopherh@1: if (chord(index) == ':') || (chord(index) == '/') || ... christopherh@1: (chord(index) == '(') || (chord(index) == ')') christopherh@1: christopherh@1: break christopherh@1: end christopherh@1: christopherh@1: % copy character into shorthand christopherh@1: shorthand(tempindex) = chord(index); christopherh@1: index = index +1; christopherh@1: tempindex = tempindex +1; christopherh@1: christopherh@1: end christopherh@1: christopherh@1: end christopherh@1: christopherh@1: case '(' christopherh@1: christopherh@1: % if we have had a colon but no other switch charaters then christopherh@1: % an open bracket signifies the start of the interval list christopherh@1: if (colon && ~slash && ~closebracket && ~openbracket) christopherh@1: christopherh@1: openbracket = 1; christopherh@1: christopherh@1: index = index +1; christopherh@1: christopherh@1: while (index <= ilength) christopherh@1: christopherh@1: if (chord(index) == ':') || (chord(index) == '/') || ... christopherh@1: (chord(index) == '(') || (chord(index) == ')') christopherh@1: christopherh@1: break christopherh@1: end christopherh@1: christopherh@1: % copy character into intervals christopherh@1: intervals(tempindex) = chord(index); christopherh@1: index = index +1; christopherh@1: tempindex = tempindex +1; christopherh@1: christopherh@1: end christopherh@1: christopherh@1: if(index > ilength) christopherh@1: errormessage = sprintf(['Error in parsechord: \nInterval list brackets not closed in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: end christopherh@1: christopherh@1: else christopherh@1: errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: end christopherh@1: christopherh@1: case ')' christopherh@1: christopherh@1: christopherh@1: % if we find a closing bracket then we should either be at christopherh@1: % the end of the symbol or there should be a slash to follow christopherh@1: if (colon && openbracket && ~slash && ~closebracket) christopherh@1: christopherh@1: closebracket = 1; christopherh@1: index = index +1; christopherh@1: christopherh@1: else christopherh@1: errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: end christopherh@1: christopherh@1: % check to see that the brackets contained something christopherh@1: if isempty(intervals) christopherh@1: errormessage = sprintf(['Error in parsechord: \nBrackets contain no intervals in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: end christopherh@1: christopherh@1: christopherh@1: case '/' christopherh@1: % forward slash should be followed by an interval string christopherh@1: christopherh@1: slash = 1; christopherh@1: christopherh@1: % move on to next character to process the expected bass interval christopherh@1: index = index +1; christopherh@1: christopherh@1: % check that we haven't overun the end of the symbol string christopherh@1: if(index > ilength) christopherh@1: errormessage = sprintf(['Error in parsechord: \nNo bass interval "/" at end of chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: end christopherh@1: christopherh@1: % check that if we have had an open bracket that it also christopherh@1: % had a closed bracket christopherh@1: if(xor(openbracket,closebracket)) christopherh@1: errormessage = sprintf(['Error in parsechord: \nFound "/" before closing bracket in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: end christopherh@1: christopherh@1: % check that the previous character was not a ':' christopherh@1: if(chord(index-2) == ':') christopherh@1: errormessage = sprintf(['Error in parsechord: \nFound "/" directly after ":" in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: end christopherh@1: christopherh@1: christopherh@1: while( index <= ilength ) christopherh@1: christopherh@1: % if we find a switch character after a slash then christopherh@1: % the symbol is incorrect christopherh@1: if (chord(index) == ':') || (chord(index) == '/') || ... christopherh@1: (chord(index) == '(') || (chord(index) == ')') christopherh@1: christopherh@1: errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength +1; christopherh@1: christopherh@1: else christopherh@1: christopherh@1: % copy remaining characters into bass christopherh@1: bass(tempindex) = chord(index); christopherh@1: index = index +1; christopherh@1: tempindex = tempindex +1; christopherh@1: end christopherh@1: end christopherh@1: christopherh@1: otherwise christopherh@1: errormessage = sprintf(['Error in parsechord: \nUnrecognised chord "' chord '"\n']); christopherh@1: success = 0; christopherh@1: index = ilength + 1; christopherh@1: end christopherh@1: christopherh@1: end christopherh@1: end christopherh@1: christopherh@1: if (verbose == 1) && (success == 0) christopherh@1: fprintf(1,errormessage); christopherh@1: end christopherh@1: christopherh@1: