annotate chordtools/parsechord.m @ 1:8973548174c1 tip

adding tools to repo
author christopherh
date Mon, 06 May 2013 14:43:47 +0100
parents
children
rev   line source
christopherh@1 1 %
christopherh@1 2 %PARSECHORD parse chord symbol to its constituent string elements
christopherh@1 3 %
christopherh@1 4 % [rootnote, shorthand, intervals, bass, success, errormessage]
christopherh@1 5 % = parsechord(chord, {verbose})
christopherh@1 6 %
christopherh@1 7 % Parses the chord symbol string "chord" into its separate string elements.
christopherh@1 8 %
christopherh@1 9 % NOTE: This function does not check validity of the chord elements, it
christopherh@1 10 % merely separates them according to the chord syntax.
christopherh@1 11 % To obtain chord elements with included validity check use GETCHORDINFO.
christopherh@1 12 %
christopherh@1 13 % Success = 1 if symbols parsed correctly, 0 otherwise.
christopherh@1 14 %
christopherh@1 15 % If optional argument 'verbose' is 1, function prints any errormessage to
christopherh@1 16 % the screen.
christopherh@1 17 %
christopherh@1 18 % returns: rootnote (note string)
christopherh@1 19 % shorthand (shorthand string)
christopherh@1 20 % intervals (interval-list string)
christopherh@1 21 % bass (interval string)
christopherh@1 22 % success (boolean)
christopherh@1 23 % errormessage (string)
christopherh@1 24 %
christopherh@1 25 % See also: getchordinfo
christopherh@1 26 %
christopherh@1 27 % Author: Christopher Harte, March 2009
christopherh@1 28 %
christopherh@1 29 % Copyright: Centre for Digital Music, Queen Mary University of London 2005
christopherh@1 30 %
christopherh@1 31 % This file is part of the C4DM Chord Toolkit V2.0
christopherh@1 32 %
christopherh@1 33 % The C4DM Chord Toolkit is free software; you can redistribute it and/or
christopherh@1 34 % modify it under the terms of the GNU General Public License as published
christopherh@1 35 % by the Free Software Foundation; either version 2 of the License, or
christopherh@1 36 % (at your option) any later version.
christopherh@1 37 %
christopherh@1 38 % The C4DM Chord Toolkit is distributed in the hope that it will be useful,
christopherh@1 39 % but WITHOUT ANY WARRANTY; without even the implied warranty of
christopherh@1 40 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
christopherh@1 41 % GNU General Public License for more details.
christopherh@1 42 %
christopherh@1 43 % You should have received a copy of the GNU General Public License
christopherh@1 44 % along with the C4DM Toolkit; if not, write to the Free Software
christopherh@1 45 % Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
christopherh@1 46
christopherh@1 47 %
christopherh@1 48 function [rootnote, shorthand, intervals, bass, success, errormessage] = parsechord(chord, verbose)
christopherh@1 49
christopherh@1 50 % set verbose default to 0
christopherh@1 51 if nargin <2
christopherh@1 52 verbose = 0;
christopherh@1 53 end
christopherh@1 54
christopherh@1 55 ilength = length(chord);
christopherh@1 56
christopherh@1 57 % initialise variables
christopherh@1 58 errormessage = '';
christopherh@1 59 rootnote = '';
christopherh@1 60 shorthand = '';
christopherh@1 61 intervals = '';
christopherh@1 62 bass = '';
christopherh@1 63
christopherh@1 64 success = 1;
christopherh@1 65 index = 1;
christopherh@1 66
christopherh@1 67
christopherh@1 68 % check for 'no chord' symbol
christopherh@1 69 if chord(index) == 'N'
christopherh@1 70 rootnote = chord(index);
christopherh@1 71 index = index +1;
christopherh@1 72 % check to see there are no further characters
christopherh@1 73 if(index<=ilength)
christopherh@1 74 errormessage = sprintf(['Error in parsechord: \nExtra characters after "no chord" symbol "' chord '"\n']);
christopherh@1 75 success = 0;
christopherh@1 76 end
christopherh@1 77 else
christopherh@1 78 % parse thechord symbol
christopherh@1 79
christopherh@1 80 % the first part of the symbol before a switch character should be the root note
christopherh@1 81 while ((index <=ilength ))
christopherh@1 82
christopherh@1 83 if (chord(index) == ':') || (chord(index) == '/') || ...
christopherh@1 84 (chord(index) == '(') || (chord(index) == ')')
christopherh@1 85
christopherh@1 86 break
christopherh@1 87 end
christopherh@1 88
christopherh@1 89 rootnote(index) = chord(index);
christopherh@1 90 index = index+1;
christopherh@1 91
christopherh@1 92 if(index > ilength) || (chord(index) == '/')
christopherh@1 93 % if chord is a rootnote on its own or with just a bass note
christopherh@1 94 % then it is a major chord therefore set shorthand to 'maj'
christopherh@1 95 shorthand = 'maj';
christopherh@1 96 end
christopherh@1 97 end
christopherh@1 98
christopherh@1 99 % initialise booleans to record which switch characters we have found
christopherh@1 100 colon = 0;
christopherh@1 101 openbracket = 0;
christopherh@1 102 closebracket = 0;
christopherh@1 103 slash = 0;
christopherh@1 104
christopherh@1 105 % parse the rest of the chord symbol
christopherh@1 106 while(index <= ilength)
christopherh@1 107
christopherh@1 108 % reset temporary index
christopherh@1 109 tempindex = 1;
christopherh@1 110
christopherh@1 111 switch(chord(index))
christopherh@1 112
christopherh@1 113 case ':'
christopherh@1 114
christopherh@1 115 % if we find a colon after any switch characters have
christopherh@1 116 % already occured then the symbol is incorrect
christopherh@1 117 if (colon || openbracket || closebracket || slash)
christopherh@1 118 errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']);
christopherh@1 119 success = 0;
christopherh@1 120 index = ilength+1;
christopherh@1 121 else
christopherh@1 122
christopherh@1 123 % found the first instance of a colon character
christopherh@1 124 colon = 1;
christopherh@1 125
christopherh@1 126 index = index +1;
christopherh@1 127
christopherh@1 128 if(index > ilength)
christopherh@1 129 errormessage = sprintf(['Error in parsechord: \nFound ":" at end of chord string "' chord '"\n']);
christopherh@1 130 success = 0;
christopherh@1 131 end
christopherh@1 132 % colon should be followed by a shorthand string or
christopherh@1 133 % an interval list contained in brackets
christopherh@1 134 while (index <= ilength)
christopherh@1 135
christopherh@1 136 if (chord(index) == ':') || (chord(index) == '/') || ...
christopherh@1 137 (chord(index) == '(') || (chord(index) == ')')
christopherh@1 138
christopherh@1 139 break
christopherh@1 140 end
christopherh@1 141
christopherh@1 142 % copy character into shorthand
christopherh@1 143 shorthand(tempindex) = chord(index);
christopherh@1 144 index = index +1;
christopherh@1 145 tempindex = tempindex +1;
christopherh@1 146
christopherh@1 147 end
christopherh@1 148
christopherh@1 149 end
christopherh@1 150
christopherh@1 151 case '('
christopherh@1 152
christopherh@1 153 % if we have had a colon but no other switch charaters then
christopherh@1 154 % an open bracket signifies the start of the interval list
christopherh@1 155 if (colon && ~slash && ~closebracket && ~openbracket)
christopherh@1 156
christopherh@1 157 openbracket = 1;
christopherh@1 158
christopherh@1 159 index = index +1;
christopherh@1 160
christopherh@1 161 while (index <= ilength)
christopherh@1 162
christopherh@1 163 if (chord(index) == ':') || (chord(index) == '/') || ...
christopherh@1 164 (chord(index) == '(') || (chord(index) == ')')
christopherh@1 165
christopherh@1 166 break
christopherh@1 167 end
christopherh@1 168
christopherh@1 169 % copy character into intervals
christopherh@1 170 intervals(tempindex) = chord(index);
christopherh@1 171 index = index +1;
christopherh@1 172 tempindex = tempindex +1;
christopherh@1 173
christopherh@1 174 end
christopherh@1 175
christopherh@1 176 if(index > ilength)
christopherh@1 177 errormessage = sprintf(['Error in parsechord: \nInterval list brackets not closed in chord "' chord '"\n']);
christopherh@1 178 success = 0;
christopherh@1 179 end
christopherh@1 180
christopherh@1 181 else
christopherh@1 182 errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']);
christopherh@1 183 success = 0;
christopherh@1 184 index = ilength +1;
christopherh@1 185 end
christopherh@1 186
christopherh@1 187 case ')'
christopherh@1 188
christopherh@1 189
christopherh@1 190 % if we find a closing bracket then we should either be at
christopherh@1 191 % the end of the symbol or there should be a slash to follow
christopherh@1 192 if (colon && openbracket && ~slash && ~closebracket)
christopherh@1 193
christopherh@1 194 closebracket = 1;
christopherh@1 195 index = index +1;
christopherh@1 196
christopherh@1 197 else
christopherh@1 198 errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']);
christopherh@1 199 success = 0;
christopherh@1 200 index = ilength +1;
christopherh@1 201 end
christopherh@1 202
christopherh@1 203 % check to see that the brackets contained something
christopherh@1 204 if isempty(intervals)
christopherh@1 205 errormessage = sprintf(['Error in parsechord: \nBrackets contain no intervals in chord "' chord '"\n']);
christopherh@1 206 success = 0;
christopherh@1 207 index = ilength +1;
christopherh@1 208 end
christopherh@1 209
christopherh@1 210
christopherh@1 211 case '/'
christopherh@1 212 % forward slash should be followed by an interval string
christopherh@1 213
christopherh@1 214 slash = 1;
christopherh@1 215
christopherh@1 216 % move on to next character to process the expected bass interval
christopherh@1 217 index = index +1;
christopherh@1 218
christopherh@1 219 % check that we haven't overun the end of the symbol string
christopherh@1 220 if(index > ilength)
christopherh@1 221 errormessage = sprintf(['Error in parsechord: \nNo bass interval "/" at end of chord "' chord '"\n']);
christopherh@1 222 success = 0;
christopherh@1 223 end
christopherh@1 224
christopherh@1 225 % check that if we have had an open bracket that it also
christopherh@1 226 % had a closed bracket
christopherh@1 227 if(xor(openbracket,closebracket))
christopherh@1 228 errormessage = sprintf(['Error in parsechord: \nFound "/" before closing bracket in chord "' chord '"\n']);
christopherh@1 229 success = 0;
christopherh@1 230 index = ilength +1;
christopherh@1 231 end
christopherh@1 232
christopherh@1 233 % check that the previous character was not a ':'
christopherh@1 234 if(chord(index-2) == ':')
christopherh@1 235 errormessage = sprintf(['Error in parsechord: \nFound "/" directly after ":" in chord "' chord '"\n']);
christopherh@1 236 success = 0;
christopherh@1 237 index = ilength +1;
christopherh@1 238 end
christopherh@1 239
christopherh@1 240
christopherh@1 241 while( index <= ilength )
christopherh@1 242
christopherh@1 243 % if we find a switch character after a slash then
christopherh@1 244 % the symbol is incorrect
christopherh@1 245 if (chord(index) == ':') || (chord(index) == '/') || ...
christopherh@1 246 (chord(index) == '(') || (chord(index) == ')')
christopherh@1 247
christopherh@1 248 errormessage = sprintf(['Error in parsechord: \nIncorrect character sequence in chord "' chord '"\n']);
christopherh@1 249 success = 0;
christopherh@1 250 index = ilength +1;
christopherh@1 251
christopherh@1 252 else
christopherh@1 253
christopherh@1 254 % copy remaining characters into bass
christopherh@1 255 bass(tempindex) = chord(index);
christopherh@1 256 index = index +1;
christopherh@1 257 tempindex = tempindex +1;
christopherh@1 258 end
christopherh@1 259 end
christopherh@1 260
christopherh@1 261 otherwise
christopherh@1 262 errormessage = sprintf(['Error in parsechord: \nUnrecognised chord "' chord '"\n']);
christopherh@1 263 success = 0;
christopherh@1 264 index = ilength + 1;
christopherh@1 265 end
christopherh@1 266
christopherh@1 267 end
christopherh@1 268 end
christopherh@1 269
christopherh@1 270 if (verbose == 1) && (success == 0)
christopherh@1 271 fprintf(1,errormessage);
christopherh@1 272 end
christopherh@1 273
christopherh@1 274