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