[PATCH] chord names language

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH] chord names language

Valentin Villenave
Administrator
It seems that this mail hasn't gone through (which is probably why I
didn't get any answers). Reposting with my gmail account.


---------- Forwarded message ----------
From: Valentin Villenave <[hidden email]>
Date: Sun, Nov 21, 2010 at 11:06 AM
Subject: [PATCH] chord names language
To: [hidden email]


Greetings everybody, hi Carl,

I'm having a look at chord names, and I think I have something to suggest.

Here's the current definition of note-name->markup:

(define-public (note-name->markup pitch lowercase?)
 "Return pitch markup for PITCH."
 (make-line-markup
  (list
   (make-simple-markup
    (conditional-string-downcase
     (vector-ref #("C" "D" "E" "F" "G" "A" "B") (ly:pitch-notename pitch))
     lowercase?))
   (accidental->markup (ly:pitch-alteration pitch)))))

As you can see, the note name vector is hardcoded; that's convenient
but not very elegant. How about retrieving note names from the
pitchnames alist instead? Not only would that be more elegant, but it
would also allow to (optionally) specify a different langauge, or take
into account the current input language:

diff --git a/scm/chord-name.scm b/scm/chord-name.scm
index 7f5909b..2853102 100644
--- a/scm/chord-name.scm
+++ b/scm/chord-name.scm
@@ -59,15 +59,38 @@
       (make-hspace-markup (if (= alteration SHARP) 0.2 0.1))
       ))))

+(define (note-names-vector alist)
+  "Extract note names from a pitchnames ALIST."
+  (let ((name-ls '()))
+    (map (lambda (x)
+          (let* ((pitch (cdr x))
+                 (alteration (ly:pitch-alteration pitch)))
+            (if (eq? alteration 0)
+                (set! name-ls (cons
+                               (string-capitalize (symbol->string (car x)))
+                               name-ls)))))
+         alist)
+    (list->vector (reverse name-ls))))
+
-(define-public (note-name->markup pitch lowercase?)
+(define-public (note-name->markup pitch lowercase? . input-language)
  "Return pitch markup for PITCH."
-  (make-line-markup
-   (list
-    (make-simple-markup
-     (conditional-string-downcase
-      (vector-ref #("C" "D" "E" "F" "G" "A" "B") (ly:pitch-notename pitch))
-      lowercase?))
-    (accidental->markup (ly:pitch-alteration pitch)))))
+  (let* ((get-pitchnames (lambda (x)
+                          (ly:assoc-get (string->symbol x)
+                                        language-pitch-names)))
+        (alist (get-pitchnames default-language)))
+    (if input-language
+       (cond ((string? input-language)
+              (set! alist (get-pitchnames input-language)))
+             ((boolean? input-language))
+             (set! alist pitchnames)))
+    (make-line-markup
+     (list
+      (make-simple-markup
+       (conditional-string-downcase
+       (vector-ref (note-names-vector alist)
+                   (ly:pitch-notename pitch))
+       lowercase?))
+      (accidental->markup (ly:pitch-alteration pitch))))))

To work, this also needs the pitchnames alist to be be declared much
earlier, which is why I suggested this other patch:
http://codereview.appspot.com/3247041/

You may wonder what the point is, well it's because I've been looking
at http://code.google.com/p/lilypond/issues/detail?id=1367 initially,
and there's a FIXME in pitch.cc that says
/* FIXME
  Merge with *pitch->text* funcs in chord-name.scm  */
so I wanted to have a look, and then I tried to move the
Note_name_engraver to a pure Scheme engraver, that would rely on the
note-name->markup function. More on that later!

Cheers,
Valentin.

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

Carl Sorensen
Hi Valentin.


On 12/7/10 9:42 AM, "Valentin Villenave" <[hidden email]> wrote:

> It seems that this mail hasn't gone through (which is probably why I
> didn't get any answers). Reposting with my gmail account.
>
>
> ---------- Forwarded message ----------
> From: Valentin Villenave <[hidden email]>
> Date: Sun, Nov 21, 2010 at 11:06 AM
> Subject: [PATCH] chord names language
> To: [hidden email]
>
>
> Greetings everybody, hi Carl,
>
> I'm having a look at chord names, and I think I have something to suggest.
>
> Here's the current definition of note-name->markup:
>
> (define-public (note-name->markup pitch lowercase?)
>  "Return pitch markup for PITCH."
>  (make-line-markup
>   (list
>    (make-simple-markup
>     (conditional-string-downcase
>      (vector-ref #("C" "D" "E" "F" "G" "A" "B") (ly:pitch-notename pitch))
>      lowercase?))
>    (accidental->markup (ly:pitch-alteration pitch)))))
>
> As you can see, the note name vector is hardcoded; that's convenient
> but not very elegant. How about retrieving note names from the
> pitchnames alist instead? Not only would that be more elegant, but it
> would also allow to (optionally) specify a different langauge, or take
> into account the current input language:

Actually, we have it hardcoded in multiple lists.

We have note-name->german-markup, note-name->semi-german-markup, and
note-name->italian-markup as well.

I sketch out an architecture below that might allow us to do

pitch->markup

in the current language, and have it work out just that way.

>
> diff --git a/scm/chord-name.scm b/scm/chord-name.scm
> index 7f5909b..2853102 100644
> --- a/scm/chord-name.scm
> +++ b/scm/chord-name.scm
> @@ -59,15 +59,38 @@
>        (make-hspace-markup (if (= alteration SHARP) 0.2 0.1))
>        ))))
>
> +(define (note-names-vector alist)
> +  "Extract note names from a pitchnames ALIST."
> +  (let ((name-ls '()))
> +    (map (lambda (x)
> +          (let* ((pitch (cdr x))
> +                 (alteration (ly:pitch-alteration pitch)))
> +            (if (eq? alteration 0)

This code won't work for German and Norwegian note names, where b is what
english calls b flat, and h is what english calls b.  There needs to be
something more general, and I'm not exactly sure what it is.

Perhaps the note name files should define both a pitch and a base name for
each of the pitches, and then we look up the base name from the pitch in the
given language, instead of trying to fake it with some other function.

I'm thinking that perhaps the lists in scm/define-note-names.scm would look
like

(nederlands . ((entry-names . (
                              (ceses . ,(ly:make-pitch -1 0 DOUBLE-FLAT))
                              ...
                              ))
               (display-names . (
                                ((0 DOUBLE-FLAT) . "C")
                                ((0 SEMI-FLAT) . "C")
                              ...
                                ))))

and then we'd need to modify the functions that get the pitch-name-alist to
get the entry-names key from the language alist.  The markup we'd get by
getting  display-names alist, and we'd do something like

(define (pitch->markup pitch)
  (let ((note-name (ly:pitch-notename pitch))
        (alteration (ly:pitch-alteration pitch)))
   (assoc-get (list note-name alteration) display-names-alist "")))



> +                (set! name-ls (cons
> +                               (string-capitalize (symbol->string (car x)))
> +                               name-ls)))))
> +         alist)
> +    (list->vector (reverse name-ls))))
> +
> -(define-public (note-name->markup pitch lowercase?)
> +(define-public (note-name->markup pitch lowercase? . input-language)
>   "Return pitch markup for PITCH."
> -  (make-line-markup
> -   (list
> -    (make-simple-markup
> -     (conditional-string-downcase
> -      (vector-ref #("C" "D" "E" "F" "G" "A" "B") (ly:pitch-notename pitch))
> -      lowercase?))
> -    (accidental->markup (ly:pitch-alteration pitch)))))
> +  (let* ((get-pitchnames (lambda (x)
> +                          (ly:assoc-get (string->symbol x)
> +                                        language-pitch-names)))
> +        (alist (get-pitchnames default-language)))
> +    (if input-language
> +       (cond ((string? input-language)
> +              (set! alist (get-pitchnames input-language)))
> +             ((boolean? input-language))
> +             (set! alist pitchnames)))
> +    (make-line-markup
> +     (list
> +      (make-simple-markup
> +       (conditional-string-downcase
> +       (vector-ref (note-names-vector alist)
> +                   (ly:pitch-notename pitch))
> +       lowercase?))
> +      (accidental->markup (ly:pitch-alteration pitch))))))
>
> To work, this also needs the pitchnames alist to be be declared much
> earlier, which is why I suggested this other patch:
> http://codereview.appspot.com/3247041/
>
> You may wonder what the point is, well it's because I've been looking
> at http://code.google.com/p/lilypond/issues/detail?id=1367 initially,
> and there's a FIXME in pitch.cc that says
> /* FIXME
>   Merge with *pitch->text* funcs in chord-name.scm  */
> so I wanted to have a look, and then I tried to move the
> Note_name_engraver to a pure Scheme engraver, that would rely on the
> note-name->markup function. More on that later!

This sounds great!

Carl



---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

Valentin Villenave
Administrator
On Thu, Dec 9, 2010 at 6:06 AM, Carl Sorensen <[hidden email]> wrote:
> Actually, we have it hardcoded in multiple lists.
>
> We have note-name->german-markup, note-name->semi-german-markup, and
> note-name->italian-markup as well.

Indeed, and whilst simpler it's still rather ugly.

> This code won't work for German and Norwegian note names, where b is what
> english calls b flat, and h is what english calls b.  There needs to be
> something more general, and I'm not exactly sure what it is.

Oh, indeed. Nice catch!

> Perhaps the note name files should define both a pitch and a base name for
> each of the pitches, and then we look up the base name from the pitch in the
> given language, instead of trying to fake it with some other function.
>
> I'm thinking that perhaps the lists in scm/define-note-names.scm

Does that mean I can push my define-note-names.scm patch? ;-)

> would look
> like
>
> (nederlands . ((entry-names . (
>                              (ceses . ,(ly:make-pitch -1 0 DOUBLE-FLAT))
>                              ...
>                              ))
>               (display-names . (
>                                ((0 DOUBLE-FLAT) . "C")
>                                ((0 SEMI-FLAT) . "C")
>                              ...
>                                ))))
>
> and then we'd need to modify the functions that get the pitch-name-alist to
> get the entry-names key from the language alist.  The markup we'd get by
> getting  display-names alist, and we'd do something like
>
> (define (pitch->markup pitch)
>  (let ((note-name (ly:pitch-notename pitch))
>        (alteration (ly:pitch-alteration pitch)))
>   (assoc-get (list note-name alteration) display-names-alist "")))

That could work. But wouldn't that be a tad bit overkill?

Another option is to just adapt what I suggested to the
Norwegian/German situation, by adding a has-bflat-letter? variable.
I'm sure I can do that pretty easily.

Upside: it would keep things simple.
Downside: it wouldn't be easily extensible if we are to add other
exotic note-name-languages that have more peculiar specificities. But
I can't see that happening anytime soon.

Cheers,
Valentin.

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

reinhold
In reply to this post by Carl Sorensen
Am Donnerstag, 9. Dezember 2010, um 06:06:28 schrieb Carl Sorensen:

> Actually, we have it hardcoded in multiple lists.
>
> We have note-name->german-markup, note-name->semi-german-markup, and
> note-name->italian-markup as well.
>
> I sketch out an architecture below that might allow us to do
>
> pitch->markup
>
> in the current language, and have it work out just that way.

Ahm, I don't think that will work. In particular, I don't think that using the
*INPUT* language to format *OUTPUT* is a bad idea. E.g. I'm writing everything
in German, because that's the note names I have grown up with. However, in my
scores, I sometimes use Italian note names for tunings.

Although I never work with chord mode, I can imagine someone wanting to create  
editions for both German-speaking countries and English-speaking countries. Of
course, it doesn't make sense to require that he rewrites the input file with
different note names, does it?

Rather, there should be an easy way to specify the output language, too.

Cheers,
Reinhold

--
------------------------------------------------------------------
Reinhold Kainhofer, [hidden email], http://reinhold.kainhofer.com/
 * Financial & Actuarial Math., Vienna Univ. of Technology, Austria
 * http://www.fam.tuwien.ac.at/, DVR: 0005886
 * LilyPond, Music typesetting, http://www.lilypond.org

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

Valentin Villenave
Administrator
On Thu, Dec 9, 2010 at 12:23 PM, Reinhold Kainhofer
<[hidden email]> wrote:
> Ahm, I don't think that will work. In particular, I don't think that using the
> *INPUT* language to format *OUTPUT* is a bad idea. E.g. I'm writing everything
> in German, because that's the note names I have grown up with. However, in my
> scores, I sometimes use Italian note names for tunings.

My point was not to automatically use whatever the input language is
as the output language, but to avoid hardcoding note names. If you
have a look at my patch above, you'll see that the default language is
used by default regardless of what the current input language is;
however it takes an optional argument to specify another input
language (in case one would rather use Italian note names or the
current input language, or whatever).

> Although I never work with chord mode, I can imagine someone wanting to create
> editions for both German-speaking countries and English-speaking countries. Of
> course, it doesn't make sense to require that he rewrites the input file with
> different note names, does it?

This patch is primarily intended for the NoteNames engraver, rather
than chord notation. But it should ultimately be used for both,  (let
me stress this once again) *without* changing the current behavior.

> Rather, there should be an easy way to specify the output language, too.

Hence my optional arg :-)
I think we're all on the same page here.

Cheers,
Valentin.

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

reinhold
In reply to this post by reinhold
Am Donnerstag, 9. Dezember 2010, um 12:23:25 schrieb Reinhold Kainhofer:

> Am Donnerstag, 9. Dezember 2010, um 06:06:28 schrieb Carl Sorensen:
> > Actually, we have it hardcoded in multiple lists.
> >
> > We have note-name->german-markup, note-name->semi-german-markup, and
> > note-name->italian-markup as well.
> >
> > I sketch out an architecture below that might allow us to do
> >
> > pitch->markup
> >
> > in the current language, and have it work out just that way.
>
> Ahm, I don't think that will work. In particular, I don't think that using
> the *INPUT* language to format *OUTPUT* is a bad idea.

... is a *good* idea, of course.

Cheers,
Reinhold

--
------------------------------------------------------------------
Reinhold Kainhofer, [hidden email], http://reinhold.kainhofer.com/
 * Financial & Actuarial Math., Vienna Univ. of Technology, Austria
 * http://www.fam.tuwien.ac.at/, DVR: 0005886
 * LilyPond, Music typesetting, http://www.lilypond.org

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

Carl Sorensen
In reply to this post by reinhold
On 12/9/10 4:23 AM, "Reinhold Kainhofer" <[hidden email]> wrote:

> Am Donnerstag, 9. Dezember 2010, um 06:06:28 schrieb Carl Sorensen:
>> Actually, we have it hardcoded in multiple lists.
>>
>> We have note-name->german-markup, note-name->semi-german-markup, and
>> note-name->italian-markup as well.
>>
>> I sketch out an architecture below that might allow us to do
>>
>> pitch->markup
>>
>> in the current language, and have it work out just that way.
>
> Ahm, I don't think that will work. In particular, I don't think that using the
> *INPUT* language to format *OUTPUT* is a bad idea. E.g. I'm writing everything
> in German, because that's the note names I have grown up with. However, in my
> scores, I sometimes use Italian note names for tunings.

Of course, this is true.  I completely agree with you.

>
> Rather, there should be an easy way to specify the output language, too.

Yes.

Carl


---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] chord names language

Carl Sorensen
In reply to this post by Valentin Villenave
On 12/9/10 2:10 AM, "Valentin Villenave" <[hidden email]> wrote:

> On Thu, Dec 9, 2010 at 6:06 AM, Carl Sorensen <[hidden email]> wrote:
>> Actually, we have it hardcoded in multiple lists.
>>
>> We have note-name->german-markup, note-name->semi-german-markup, and
>> note-name->italian-markup as well.
>
> Indeed, and whilst simpler it's still rather ugly.
>
>> This code won't work for German and Norwegian note names, where b is what
>> english calls b flat, and h is what english calls b.  There needs to be
>> something more general, and I'm not exactly sure what it is.
>
> Oh, indeed. Nice catch!
>
>> Perhaps the note name files should define both a pitch and a base name for
>> each of the pitches, and then we look up the base name from the pitch in the
>> given language, instead of trying to fake it with some other function.
>>
>> I'm thinking that perhaps the lists in scm/define-note-names.scm
>
> Does that mean I can push my define-note-names.scm patch? ;-)
>
>> would look
>> like
>>
>> (nederlands . ((entry-names . (
>>                              (ceses . ,(ly:make-pitch -1 0 DOUBLE-FLAT))
>>                              ...
>>                              ))
>>               (display-names . (
>>                                ((0 DOUBLE-FLAT) . "C")
>>                                ((0 SEMI-FLAT) . "C")
>>                              ...
>>                                ))))
>>
>> and then we'd need to modify the functions that get the pitch-name-alist to
>> get the entry-names key from the language alist.  The markup we'd get by
>> getting  display-names alist, and we'd do something like
>>
>> (define (pitch->markup pitch)
>>  (let ((note-name (ly:pitch-notename pitch))
>>        (alteration (ly:pitch-alteration pitch)))
>>   (assoc-get (list note-name alteration) display-names-alist "")))
>
> That could work. But wouldn't that be a tad bit overkill?
>

Perhaps.  But it keeps all of the language definitions together.

In your code, you want to avoid hard-coded alists (which I actually prefer
as they are more readable).  I can see a reason for that.  But in order to
do so, you would keep needing to introduce various flags, e.g.
has-bflat-letter? and use-accent-on-re? (which we haven't discussed yet).
This eventually becomes a set of arbitrary tests, just to allow us to
convert from symbols to strings.

IMO, it's cleaner to define the strings we want to display somewhere.  And
the most logical place to define them is in the language file.  Perhaps not
with the exact architecture I've proposed.  Perhaps as separate alist
entries including things like notename-markup, and separate-bflat, instead
of display-name for all of the pitches.

Thanks,

Carl


---
----
Join the Frogs!

Loading...