for example, to read midi names and convert to number… hmm just noticed the switch case is not needed, it was needed before but I’ve been slowly improving the code. Edit: Oops, nope it is needed or I can’t skip the “get accidental” or “get sign” case.

```
int MIDI::num(String s)
{
if (s.isEmpty()) ERROR(e::empty_string);
int midi_val;
if (STR::isInt(s))
{
midi_val = s.getIntValue();
if (midi_val < 0 || midi_val > 127) ERROR(e::num_out_of_bounds);
return midi_val;
}
s = s.toUpperCase();
octave_str.clear();
accidental_mod = 0;
accidental = '\0';
sign = '\0';
enum MODE { get_letter, get_accidental, get_sign, get_octave};
MODE mode = get_letter;
for (auto p = s.getCharPointer(); !p.isEmpty();)
{
switch (mode)
{
case get_letter:
if (!CHAR::isAnyOf(*p, "ABCDEFG")) ERROR(e::not_a_midi_letter);
letter = *p;
letter_mod = letter_to_value[letter];
mode = get_accidental;
++p;
continue;
case get_accidental:
if (!CHAR::isAnyOf(*p, "B#")) { mode = get_sign; continue; }
accidental = *p;
accidental_mod = accidental_to_value[accidental];
mode = get_sign;
++p;
continue;
case get_sign:
if (!CHAR::isAnyOf(*p, "-+")) { mode = get_octave; continue; }
sign = *p;
if (sign == '-') sign_mod = -1;
++p;
mode = get_octave;
continue;
case get_octave:
for (; !p.isEmpty(); ++p) octave_str += *p;
if (!STR::isInt(octave_str)) ERROR(e::cannot_read_octave);
octave = octave_str.getIntValue();
midi_val = (octave * sign_mod + lowest_octave*-1) * 12 + letter_mod + accidental_mod;
if (midi_val < 0 || midi_val > 127) ERROR(e::num_out_of_bounds);
continue;
}
}
return midi_val;
}
```