Hello,
In the thread about creating custom metronome markups
(http://lists.gnu.org/archive/html/lilypond-user/2008-04/msg00629.html)
and the subsequent discussion at The LilyPond Report, Valentin
expressed the wish for a convenient way to convert duration strings to
durations. Since I agreed, I thought I'd have a go at implementing an
exported scheme function in duration-scheme.cc which can be used
within lilypond files.
Attached is a patch with "My First C++ Code", which provides this
functionality. :)
Hi Neil,
This looks pretty good overall; my main complaint is that it is a bit too permissive in its parsing. Comments below:
+
+LY_DEFINE (ly_string_2_duration, "ly:string->duration",
+ 1, 0, 0, (SCM str),
+ "Convert @var{str} to a duration.")
+{
+ LY_ASSERT_TYPE (scm_is_string, str, 1);
+ string s = ly_scm2string (str);
+ stringstream stream (s);
+ int len = 0;
+ int dots = 0;
+ size_t pos = 0;
+
+ while (pos !=NPOS)
Space after !=
+ {
+ pos = s.find (".", pos);
This will allow strings like "2.asdf..". Why not just search for the first '.' and then check all subsequent characters?
+ if (pos != NPOS)
+ {
+ dots++;
+ pos++;
+ }
+ }
+ s = s.substr (0, (s.length () - dots));
+
+ stream >> len;
You need to check that all of the characters were used up in the conversion or else "2asdf." will pass. I'd suggest
if (sscanf (s.c_str (), "%d") != s.size ()) ...
since I find the C stdlib functions less unwieldy than C++ streams, particularly in simple situations.
+ if (!stream.fail () && (len && len == 1 << intlog2 (len)))
+ len = intlog2 (len);
+ else
+ {
+ if (s == "breve")
+ len = -1;
+ else if (s == "longa")
+ len = -2;
+ else if (s == "maxima")
+ len = -3;
+ else
+ {
+ len = 0;
+ dots = 0;
+ warning (_ ("invalid duration string, setting to whole note"));
Perhaps print the invalid duration string as part of the message (using _f ()).
Joe